How should I manage DbContext Lifetime in MVC Core?

As others already explained, you should use a scoped dependency for database contexts to make sure it will be properly reused. For concurrency, remember that you can query the database asynchronously too, so you might not need actual threads.

If you do need threads, i.e. background workers, then it’s likely that those will have a different lifetime than the request. As such, those threads should not use dependencies retrieved from the request scope. When the request ends and its dependency scope is being closed, disposable dependencies will be properly disposed. For other threads, this would mean that their dependencies might end up getting disposed although they still need them: Bad idea.

Instead, you should explicitly open a new dependency scope for every thread you create. You can do that by injecting the IServiceScopeFactory and creating a scope using CreateScope. The resulting object will then contain a service provider which you can retrieve your dependencies from. Since this is a seperate scope, scoped dependencies like database contexts will be recreated for the lifetime of this scope.

In order to avoid getting into the service locator pattern, you should consider having one central service your thread executes that brings together all the necessary dependencies. The thread could then do this:

using (var scope = _scopeFactory.CreateScope())
{
    var service = scope.ServiceProvider.GetService<BackgroundThreadService>();
    service.Run();
}

The BackgroundThreadService and all its dependency can then follow the common dependency injection way of receiving dependencies.

Leave a Comment