Looking at the examples of how to use db context pool I see it was designed to be used with ServiceCollection
:
var serviceProvider = new ServiceCollection()
.AddDbContextPool<AdventureWorksContext>(options => { //options })
.BuildServiceProvider();
But what about Simple Injector? is it possible to register DB pooling in the Simple Injector container?
p.s. My app is not ASP.NET MVC, it's just a kinda DAL
Pooling without dependency injection was introduced in EF Core 6.0. The poolSize parameter of the PooledDbContextFactory constructor sets the maximum number of instances retained by the pool (defaults to 1024 in EF Core 6.0, and to 128 in previous versions).
To improve performance for web applications you may consider using the context pooling feature. It is worth using only when your application has a decent load since it just caches DbContext instances for not to dispose after each request and recreate again.
Note that for a single row, EF Core is slower than EF6 unless using context pooling; this could be the cost of setting up all the scoped services for each instance (which isn't done when context pooling is on). For multiple rows, EF Core batches and EF6 doesn't, so EF Core quickly becomes much faster.
DbContext is not thread-safe. Do not share contexts between threads. Make sure to await all async calls before continuing to use the context instance. An InvalidOperationException thrown by EF Core code can put the context into an unrecoverable state.
When integrating Simple Injector in ASP.NET Core, you keep framework and third-party components inside the .NET Core configuration system. This means that enabling Entity Framework Core context pooling is done exactly as Microsoft documents it:
services.AddDbContextPool<BloggingContext>(
options => options.UseSqlServer(connectionString));
As Simple Injector does not replace the built-in configuration system, you will have to instruct Simple Injector to automatically load missing registrations (such as your DbContext
) from the .NET Core configuration system. This can be done by using the AddSimpleInjector
and UseSimpleInjector
extension methods, as shown here.
private SimpleInjector.Container container;
public void ConfigureServices(IServiceCollection services)
{
...
services.AddDbContextPool<BloggingContext>(
options => options.UseSqlServer(connectionString));
services.AddSimpleInjector(container, options =>
{
options.AddAspNetCore();
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseSimpleInjector(container);
container.Verify();
...
}
Using this setup, the BloggingContext
can be injected into any component that is resolved from Simple Injector, while the BloggingContext
is pooled by Entity Framework. For intance:
// Application compoment registered in and resolved from Simple Injector
public class CommentIsNoSpamValidator : IValidator<PostComment>
{
private readonly BloggingContext context;
// Is injected with BloggingContext from IServiceCollection
public CommentIsNoSpamValidator(BloggingContext context)
{
this.context = context;
}
public IEnumerable<ValidationResult> Validate(PostComment command)
{
// Complex business logic here.
}
}
When it comes to using Entity Framework Core context pooling in a .NET Core console application, the solution will be very similar, although you will have to set up a little bit more:
public void Main()
{
var container = new Container();
var services = new ServiceCollection();
services.AddDbContextPool<BloggingContext>(
options => options.UseSqlServer(connectionString));
services.AddSimpleInjector(container);
services
.BuildServiceProvider(validateScopes: true)
.UseSimpleInjector(container);
container.Verify();
// Run application code
using (AsyncScopedLifestyle.BeginScope(container))
{
var service = container.GetInstance<MainService>();
service.DoAwesomeStuff();
}
}
So in the end, the DbContext's lifetime is managed by the MS.DI scope, but that scope is managed by Simple Injector's scope.
In case you are building a library, i.e. a non-startup project, please stop what you're doing. Only the application's startup assembly should have a Composition Root, and only the Composition Root should use a DI Container (such as Simple Injector or MS.DI's ServiceCollection
). All other libraries in your application should stay oblivious of the (possible) existence of a Container.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With