Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Entity Framework Core DbContext Pooling with Simple Injector

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

like image 576
user1178399 Avatar asked Aug 31 '18 08:08

user1178399


People also ask

Does EF core use connection pooling?

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).

Which method enables pooling when you register a DbContext with the services for an application?

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.

Is EF core faster than EF6?

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.

Is EF core DbContext thread safe?

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.


1 Answers

EF Core DbContext pooling in ASP.NET Core

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.
    }
}

EF Core DbContext pooling in a .NET (Core) Console application

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.

EF Core DbContext pooling in a library

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.

like image 192
Steven Avatar answered Jan 01 '23 09:01

Steven