A small JSON database for small projects.
Add the appropriate NuGet package to your project. See alternatives to local storage for more options.
$ dotnet add package JsonDb
To use the JSON database, you first need to configure your dependency injection container with the desired implementation. The bellow is an example using LocalStorage
.
IServiceCollection services = ...
services.AddLocalJsonDb( options =>
{
options.DbPath = "db";
} );
This gives us access to an IJsonDbFactory
, injected wherever we need it. Here's an example to retrieve users from a users.json
file.
public class MyService
{
private readonly IJsonDb db;
public MyService( IJsonDbFactory jsonDbFactory )
{
db = jsonDbFactory.GetJsonDb();
}
public Task<IEnumerable<User>> GetUsersAsync()
{
var users = await db.GetCollectionAsync<User>( "users" );
return ( users );
}
}
The collections implement an IEnumerable<T>
, which means we can iterate directly or use LINQ extensions to query our collection.
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
...
public class MyService
{
...
public Task<User> GetUserAsync( int id )
{
var users = await db.GetCollectionAsync<User>( "users" );
var user = users.Where( x => x.Id == id )
.SingleOrDefault();
return ( user );
}
}
Similarly, removing items from our collection also uses a predicate.
users.Remove( x => x.Id == 2 );
When we add or remove items to/from our collection, these changes aren't automatically written to the source. The reason why is that this would be much slower when adding multiple items. Therefore, after adding or removing items we need to write the changes.
await users.WriteAsync();
If you just need a "readonly" collection (no physical write support), you can also use the JsonDbCollection
helpers to directly read JSON content into a collection.
// reading directly from a JSON file
var usersFile = await JsonDbCollection.ReadFileAsync<User>( "path/users.json" );
// reading directly from an URI
var stuffUrl = await JsonDbCollection.ReadUrlAsync<User>( "https://gist.githubusercontent.com/goncalo-oliveira/2e7386336652721c06943e9099e4c622/raw/ee21a456573cfff79ebc01cb1b8daa1f9294b364/jsondb-users.json" );
Encryption of the data at rest is possible by using a IJsonCollectionAdapter
instance. This can be passed through in the options when setting up the dependency injection container.
services.AddLocalJsonDb( options =>
{
options.DbPath = "db";
options.CollectionAdapter = new EncryptedJsonCollectionAdapter( encryptionKey );
} );
The above example uses an adapter that encrypts (and decrypts) data using an AES algorithm with a 256 bit encryption key. If you need a different adapter, you can implement IJsonCollectionAdapter
yourself.
Both the local storage and the S3 compatible storage implementations can use adapters. Ad-hoc
JsonDbCollection
helpers don't support this feature.
There is also support for AWS S3 compatible storage. Install the package JsonDb.S3
instead and add the following to the container setup
IServiceCollection services = ...
// example with DigitalOcean's S3 compatible Spaces
services.AddS3JsonDb( options =>
{
options.ServiceUrl = "https://ams3.digitaloceanspaces.com/";
options.BucketName = "digitalocean-space-name";
options.AccessKey = "digitalocean-access-key";
options.SecretKey = "digitalocean-secret-key";
options.DbPath = "jsondb";
} );
If you'd like to write your own, install the package JsonDb.Core
and implement the following interfaces:
- IJsonDbFactory
- IJsonDb
- IJsonCollection
You can derive your collection from InMemoryJsonCollection<T>
and just implement the WriteAsync
method.