首页 > 解决方案 > ASP.NET Core DI 与 Simple Injector 共享 DbContext

问题描述

我正在建立一个 ASP.NET Core 项目,并根据我在Tripod项目上的工作遵循 CQRS 模式。我遵循了 Simple Injector 集成指南,但在某一点上有点困惑......我想继续使用该UseInMemoryDatabase选项进行测试,并且只能找到使用 Core DIAddDbContext方法的示例。

我的 DbContext 实现了几个接口:

public class EntityDbContext : DbContext,
    IUnitOfWork,
    IReadEntities,
    IWriteEntities
{
    // code here
}

我在Startup.ConfigureServices方法中这样做:

services.AddDbContext<EntityDbContext>(options => options.UseInMemoryDatabase("Snoogans"));

并在 Startup.Configure 方法中遵循 SI 集成指南:

container.Register<IUnitOfWork, xxxx>();
container.Register<IReadEntities, xxxx>();
container.Register<IWriteEntities, xxxx>();

我是否能够通过交叉线将核心注册到每个目标的插件,还是应该直接在 SI 中注册上下文?

== 我正在玩 Tripod 的原始概念:

var contextRegistration =
    lifestyle.CreateRegistration<EntityDbContext, EntityDbContext>(container);
container.AddRegistration(typeof(EntityDbContext), contextRegistration);
container.AddRegistration(typeof(IUnitOfWork), contextRegistration);
container.AddRegistration(typeof(IWriteEntities), contextRegistration);
container.AddRegistration(typeof(IReadEntities), contextRegistration);

试图用 SI 做所有事情,但不确定我如何获得 3 个接口的注册:

container.Register<EntityDbContext>(() =>
{
    var optionsBuilder =
        new DbContextOptionsBuilder<EntityDbContext>().UseInMemoryDatabase("Snoogans");
    return new EntityDbContext(optionsBuilder.Options);
});
container.AddRegistration<IUnitOfWork>(xxxx);
container.AddRegistration<IReadEntities>(xxxx);
container.AddRegistration<IWriteEntities>(xxxx);

标签: c#asp.net-coredependency-injectionentity-framework-coresimple-injector

解决方案


我是否能够通过交叉线将核心注册到每个目标的插件,还是应该直接在 SI 中注册上下文?

两种选择都是可行的。您可以选择将 DbContext 直接注册到 Simple Injector 中。这通常是最明显的选择,因为您的 DbContext 是一个应用程序组件。应用程序组件通常应该在您的应用程序容器(即 Simple Injector)中注册,而不是在框架的注册系统(即ServiceCollection)中。

然而,在注册DbContext方面,与 ASP.NET Core 配置系统有一些紧密的集成。这可以更直接地在那里进行注册,并简单地从 Simple Injector 进行交叉接线。这让配置系统可以控制 DbContext 的创建和销毁。这在执行 DbContext 池之类的操作时变得特别有价值,因为此池功能与此配置和注册 API 紧密耦合。

通常,这两个选项都非常简单,但是因为您的 DbContext 实现了您想要单独注册的多个接口,这会导致您的注册变得更加复杂。如果您也使用内置的 DI 容器,情况也会如此,因此这并非特定于 Simple Injector。

在您的情况下,纯粹在 Simple Injector 中进行注册将如下所示:

var reg = Lifestyle.Scoped.CreateRegistration(() =>
    {
        var optionsBuilder =
            new DbContextOptionsBuilder<EntityDbContext>().UseInMemoryDatabase("Snoogans");
        return new EntityDbContext(optionsBuilder.Options);
    },
    container);

container.AddRegistration<IUnitOfWork>(reg);
container.AddRegistration<IReadEntities>(reg);
container.AddRegistration<IWriteEntities>(reg);

如果您选择从 .NET Core 配置系统交叉连接 DbContext,您的配置将如下所示:

// Add to the built-in ServiceCollection
services.AddDbContext<EntityDbContext>(options => options.UseInMemoryDatabase("Snoogans"));

// Cross-wire in Simple Injector
container.CrossWire<EntityDbContext>(app);

// Pull that registration out of Simple Injector and use it for the interface registrations
var reg = container.GetRegistration(typeof(EntityDbContext)).Registration;

// Same as before
container.AddRegistration<IUnitOfWork>(reg);
container.AddRegistration<IReadEntities>(reg);
container.AddRegistration<IWriteEntities>(reg);

如果您不使用 Simple Injector,而是纯粹使用 .NET Core 的内置 DI 容器,则注册将如下所示:

services.AddDbContext<EntityDbContext>(options => options.UseInMemoryDatabase("Snoogans"));

services.AddScoped<IUnitOfWork>(c => c.GetRequiredService<EntityDbContext>());
services.AddScoped<IReadEntities>(c => c.GetRequiredService<EntityDbContext>());
services.AddScoped<IWriteEntities>(c => c.GetRequiredService<EntityDbContext>());

推荐阅读