Using RavenDB Unit of Work and .NET Core MVC

time to read 1 min | 180 words

We were asked about best practices for managing the RavenDB session (unit of work) in a .NET Core MVC application. I thought it is interesting enough to warrant its own post.

RavenDB’s client API is divided into the Document Store, which holds the overall configuration required to access a RavenDB and the Document Session, which is a short lived object implementing Unit of Work pattern and typically only used for a single request.

We’ll start by adding the RavenDB configuration to the appsettings.json file, like so:

{
"Database": {
"Urls": [
"https://a.rock-n.roll.ravendb.cloud",
"https://b.rock-n.roll.ravendb.cloud",
"https://c.rock-n.roll.ravendb.cloud",
],
"DatabaseName": "Jazz",
"CertPath": "/mnt/config/jazz.pfx",
"CertPass": null
}
}

We bind it to the following strongly typed configuration class:

public class Settings
{
public DatabaseSettings Database { get; set; }
public class DatabaseSettings
{
public string[] Urls { get; set; }
public string DatabaseName { get; set; }
public string CertPath { get;set; }
public string CertPass { get;set; }
}
}
view raw Settings.cs hosted with ❤ by GitHub

The last thing to do it to register this with the container for dependency injection purposes:

public void ConfigureServices(IServiceCollection services)
{
var settings = new Settings();
Configuration.Bind(settings);
var store = new DocumentStore
{
Urls = settings.Urls,
Database = settings.DatabaseName,
Certificate = new X509Certificate2( settings.CertPath, settings.CertPass)
};
store.Initialize();
services.AddSingleton<IDocumentStore>(store);
services.AddScoped<IAsyncDocumentSession>(serviceProvider =>
{
return serviceProvider
.GetService<IDocumentStore>()
.OpenAsyncSession();
});
}
view raw configure.cs hosted with ❤ by GitHub

We register both the Document Store and the Document Session in the container, but note that the session is registered on a scoped mode, so each connection will get a new session.

Finally, let’s make actual use of the session in a controller:

public class UsersController : Controller
{
private readonly IAsyncDocumentSession _session;
public UsersController(IAsyncDocumentSession session)
{
_session = session;
}
public async Task<IActionResult> Index()
{
var users = await session.Query<User>().ToListAsync();
return View(users);
}
}
view raw users.cs hosted with ❤ by GitHub

Note that we used to recommend having SaveChangesAsync run for you automatically, but at this time, I think it is probably better to do this explicitly.