将实体框架核心DbContext池与简单注入器一起使用

时间:2018-08-31 08:57:23

标签: entity-framework-core dbcontext simple-injector ef-core-2.1

看看如何使用数据库上下文池的示例,我发现它是设计用于ServiceCollection的:

var serviceProvider = new ServiceCollection()
    .AddDbContextPool<AdventureWorksContext>(options => { //options })
    .BuildServiceProvider();

但是简单喷射器呢?是否可以在Simple Injector容器中注册数据库池?

p.s。我的应用程序不是ASP.NET MVC,只是一种DAL

3 个答案:

答案 0 :(得分:5)

ASP.NET Core中的EF Core DbContext池

在ASP.NET Core中集成Simple Injector时,会将框架和第三方组件保留在.NET Core配置系统中。这意味着启用Entity Framework Core上下文池的过程与Microsoft记录的完全相同:

services.AddDbContextPool<BloggingContext>(
    options => options.UseSqlServer(connectionString));

但是,与简单注入器does not replace the built-in configuration system一样,您将必须instruct简单注入器才能从.NET Core配置系统自动加载缺少的注册信息(例如DbContext)。可以通过使用EnableSimpleInjectorCrossWiringAutoCrossWireAspNetComponents扩展方法来完成,如此处所示。

private SimpleInjector.Container container;

public void ConfigureServices(IServiceCollection services) {
    ...

    services.EnableSimpleInjectorCrossWiring(this.container);
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
    ...

    container.AutoCrossWireAspNetComponents(app);
}

使用此设置,BloggingContext可以注入到从简单注入器解析的任何组件中,而BloggingContext由实体框架池化。

.NET(核心)控制台应用程序中的EF Core DbContext池

不幸的是,当涉及到在.NET Core控制台应用程序中使用Entity Framework Core上下文池时,涉及的内容更多。这是因为上下文池与新的MS.DI抽象机制高度集成,而Simple Injector的交叉接线功能目前需要ASP.NET Core(这是我们在未来版本中might improve所采用的功能)。

当前可以在.NET Core控制台应用程序中设置EF上下文池,如下所示:

static void Main(string[] args)
{
    var container = new Container();
    container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

    // Register stuff
    RegisterBloggingContext(container);

    container.Verify();

    // Start using Simple Injector as usual:
    using (AsyncScopedLifestyle.BeginScope(container))
    {
        var c = container.GetInstance<SomeComponentDependingOnBloggingContext>();
    }
}
// Magic starts here:
private static void RegisterBloggingContext(Container container)
{
    // Build an IServiceProvider with DbContext pooling and resolve a scope factory.
    var scopeFactory = new ServiceCollection()
        .AddDbContextPool<BloggingContext>(o => o.UseSqlServer(connectionString))
        .BuildServiceProvider(validateScopes: true)
        .GetRequiredService<IServiceScopeFactory>();

    // Use that scope factory to register an IServiceScope into Simple Injector
    container.Register<IServiceScope>(scopeFactory.CreateScope, Lifestyle.Scoped);

    // Cross wire the DbContext by resolving the IServiceScope and requesting the
    // DbContext from that scope.
    container.Register(() => container.GetInstance<IServiceScope>().ServiceProvider
        .GetService<BloggingContext>(),
        Lifestyle.Scoped);
}

此代码的作用是允许EF将其组件注册到MS.DI ServiceCollection类中。使用该服务集合,可以构建一个IServiceProvider(MS.DI容器),并从该容器中请求一个IServiceScopeFactory

IServiceScopeFactory用于注册IServiceScope。这是MS.DI的范围界定机制。通过在Simple Injector中注册它,MS.DI范围将由Simple Injector管理。这意味着,当放置简单注入器Scope时,IServiceScope(因为IServiceScope实现IDisposable)也将随之存在,并且已注册的DbContext将与发送回池(在处理DbContext时会发生这种情况)。

最后一部分是DbContext本身的“交叉布线”。通过注册将首先从Simple Injector请求IServiceScope的委托来完成。同样,由于IServiceScope是从Simple Injector解析的,因此它也将由Simple Injector处置(因为IServiceScope实现了IDisposable)。使用解析的IServiceScope,可以从该MS.DI范围请求DbContext

最后,DbContext的生存期由MS.DI范围管理,但该范围由Simple Injector的范围管理。

这有点令人讨厌,但不幸的是,EF Core的上下文池已深度集成到服务收集模型中。

库中的EF Core DbContext池

如果您要构建库(即非启动项目),请停止正在执行的操作。仅应用程序的启动程序集应具有Composition Root,并且只有合成根目录应使用DI容器(例如,简单注入器或MS.DI的`ServiceCollection)。您应用程序中的所有其他库都应忽略(可能)容器的存在:

  

如果使用DI容器,则“合成根”应该是唯一使用DI容器的地方。在合成根目录之外使用DI容器会导致服务定位器反模式(source

答案 1 :(得分:0)

您可以使用

container.Register(() => serviceProvider.GetRequiredService<AdventureWorksContext>());

让ServiceProvider根据请求解决依赖关系。

答案 2 :(得分:0)

除了@Steven的出色答案之外,这是他的控制台应用程序答案,但使用array ( 0 => '', 1 => '8', 2 => '8', 3 => '8', 4 => '8', 5 => '8', 6 => '1', 7 => '1000', 8 => '2020', ) 具有上下文(隐式)。

UseInternalServiceProvider

Demo,您想使用var services = new ServiceCollection(); services.AddEntityFrameworkSqlServer(); services.AddSingleton<Microsoft.Extensions.Logging.ILoggerFactory>(new Microsoft.Extensions.Logging.LoggerFactory()); services.AddSingleton<IInterface>(new MyImplemenation()); services.AddDbContextPool<EFViewAndManyToManyDb>(optionsBuilder => { optionsBuilder.UseSqlServer(""); }); services.AddSimpleInjector(container); services .BuildServiceProvider(validateScopes: true) .UseSimpleInjector(container); 。 TLDR:如果您的UseInternalServiceProvider具有依赖项,例如DbContext。您还需要添加IInterface Nuget程序包。