A library for managing the lifetime of Entity Framework Core DbContext instances.
Note re package versioning: Please use the version of this library which matches your EF Core version.
For EF Core 6, the NuGet package can be found at Zejji.DbContextScope.EFCore6.
To avoid having a separate NuGet package for each EF Core version, for EF Core 7 onwards, the decision was taken to remove the EF Core version from the package name and instead have the Zejji.DbContextScope.EFCore package version number follow the EF Core version - the current NuGet package can be found at Zejji.DbContextScope.EFCore.
This package is based on the original DbContextScope repository by Mehdi El Gueddari with the following changes:
- updated for .NET 6+ and EF Core (including replacing usages of
CallContextwithAsyncLocal); - added fix for
RefreshEntitiesInParentScopemethod so that it works correctly for entities with composite primary keys; - added fix for
DbContextCollection'sCommitandCommitAsyncmethods so thatSaveChangescan be called more than once if there is aDbUpdateConcurrencyException(see this unmerged pull request in the originalDbContextScoperepository); - added the
RegisteredDbContextFactoryclass as a concrete implementation of theIDbContextFactoryinterface, which allows users to easily register factory functions for one or moreDbContexttype(s) during startup; and - added unit tests.
Mehdi El Gueddari's original article describing the thinking behind the DbContextScope library can be found here.
In summary, the library addresses the problem that injecting DbContext instances as a scoped dependency (which ordinarily results in one instance per web request) offers insufficient control over the lifetime of DbContext instances in more complex scenarios.
The DbContextScope library allows users to create scopes which control the lifetime of ambient DbContext instances, as well giving control over the exact time at which changes are saved.
For general usage instructions, see article referred to above and the original GitHub repository readme file (a copy of which is included in this repository here). Please note the Mehdime.Entity namespace has been renamed to Zejji.Entity.
- .NET 6+
- EF Core (version equal to or higher than Zejji.DbContextScope.EFCore package version)
dotnet add package Zejji.DbContextScope.EFCore
In order to start using this library, you will need to register several dependencies with the dependency injection container.
In most cases you will want DbContext instances to be constructed by the dependency injection container. You will need the following registrations:
services.AddScoped<IDbContextFactory, ServiceProviderDbContextFactory>();
services.AddScoped<IDbContextScopeFactory, DbContextScopeFactory>();
services.AddSingleton<IAmbientDbContextLocator, AmbientDbContextLocator>();Note that we use a scoped lifetime for the ServiceProviderDbContextFactory, to allow scoped dependencies
to be injected into created DbContext instances, e.g. a tenant ID accessor in a multi-tenant application
(see e.g. Finbuckle.MultiTenant).
If you are sure you will never need any scoped dependencies within your DbContext instances and know what you are doing,
it is also possible to register the IDbContextFactory and IDbContextScopeFactory with a singleton lifetime.
See here for a discussion of dependency injection lifetimes.
The RegisteredDbContextFactory class can be used in rare cases where you need more control over how DbContext instances are created. Usage is as follows:
- In
Startup.cs, register aRegisteredDbContextFactoryinstance and register one or moreDbContextfactory functions on that instance, e.g.:
using Zejji.Entity;
...
public void ConfigureServices(IServiceCollection services)
{
...
// Create an instance of the RegisteredDbContextFactory
var dbContextFactory = new RegisteredDbContextFactory();
// Register factory functions for each of the required DbContext types
dbContextFactory.RegisterDbContextType<DbContextOne>(() =>
new DbContextOne(Configuration.GetConnectionString("DatabaseOne")));
dbContextFactory.RegisterDbContextType<DbContextTwo>(() =>
new DbContextTwo(Configuration.GetConnectionString("DatabaseTwo")));
// Register the RegisteredDbContextFactory instance as a singleton
// with the dependency injection container.
services.AddSingleton<IDbContextFactory>(dbContextFactory);
...
}See also the unit tests for RegisteredDbContextFactory here.
This project is licensed under the MIT License - see the LICENSE.txt file for details
Many thanks to Mehdi El Gueddari for creating the original DbContextScope library.