.net core 注册具有多个生存期的服务

.net core 注册具有多个生存期的服务,.net-core,dependency-injection,lifetime,ef-core-2.2,.net Core,Dependency Injection,Lifetime,Ef Core 2.2,在.NETCore2.2应用程序中,我需要一个服务的暂时版本和一个作用域版本 对于“常规”服务,我可以创建两个不同的接口,一个注册为瞬态接口,另一个注册为作用域接口,但如果两者都需要DbContext,这意味着我需要创建两个DbContext(是的,一个可以只是包装器)并同时注册,但这感觉不合适 我使用的是DotnetCore的默认依赖注入框架,我对它不太熟悉。在UnityIoC中,我可以使用命名注册轻松完成这项工作: //Note: Pseudo-code void Register(IUni

在.NETCore2.2应用程序中,我需要一个服务的暂时版本和一个作用域版本

对于“常规”服务,我可以创建两个不同的接口,一个注册为瞬态接口,另一个注册为作用域接口,但如果两者都需要DbContext,这意味着我需要创建两个DbContext(是的,一个可以只是包装器)并同时注册,但这感觉不合适

我使用的是DotnetCore的默认依赖注入框架,我对它不太熟悉。在UnityIoC中,我可以使用命名注册轻松完成这项工作:

//Note: Pseudo-code
void Register(IUnityContainer container)
{   
    container.RegisterType<IMyInterface, MyClass>(
        "Transient",
        new TransientLifetimeManager()
        new InjectionConstructor(
            new ResolvedParameter<MyDbContext>("Transient")));

    container.RegisterType<IMyInterface, MyClass>(
        "PerResolve",
        new "PerResolve", new PerResolvedLifetimeManager()()
        new InjectionConstructor(
            new ResolvedParameter<MyDbContext>(PerResolve)));

    container.RegisterType<MyDbContext>("Transient", new TransientLifetimeManager());
    container.RegisterType<MyDbContext, MyClass>("PerResolve", new PerResolvedLifetimeManager());
}
//注意:伪代码
无效寄存器(IUnityContainer容器)
{   
container.RegisterType(
“暂时的”,
新的TransientLifetimeManager()
新注入构造函数(
新解析参数(“瞬态”);
container.RegisterType(
“佩雷索夫”,
新的“PerResolve”,新的PerResolvedLifetimeManager()
新注入构造函数(
新解析参数(PerResolve);
RegisterType(“Transient”,新TransientLifetimeManager());
RegisterType(“PerResolve”,新的PerResolvedLifetimeManager());
}

优点:使用IServiceProvider,如何要求瞬态分辨率与范围分辨率?

实现这一点的最简单方法是使用两个接口,如以下示例所示:

interface IMyScopedInterface
{
    void Foo();
}

interface IMyTransientInterface
{
    void Foo();
}

class MyClass : IMyTransientInterface, IMyScopedInterface
{
    public MyClass(MyDbContext dbContext)
    {
    }

    public void Foo()
    {
    }
}
然后使用以下命令注册您的类:

services.AddTransient<IMyTransientInterface, MyClass>();
services.AddScoped<IMyScopedInterface, MyClass>();
services.AddTransient();
services.addScope();
您无需对
DbContext
执行任何特殊操作即可支持此功能。让我们看看DI系统将如何解决这些服务,看看它是否能够澄清为什么会出现这种情况

  • 首先,DI系统尝试获取
    IMyScopedInterface
    的实例(通常是因为DI系统尝试实例化其构造函数采用
    IMyScopedInterface
    参数的其他服务)
  • 由于
    IMyScopedInterface
    已使用作用域生存期注册,DI系统首先查看其已为当前作用域实例化的服务集合,以查看是否已创建
    IMyScopedInterface
    。该搜索结果是空手而来的,因此DI系统随后继续创建
    MyClass
    的新实例
  • 为此,它检查
    MyClass
    的构造函数并确定它需要一个
    MyDbContext
    ,因此它通过相同的流递归回来,以获得一个
    MyDbContext
  • DI系统构造一个提供获得的
    MyDbContext
    MyClass
    实例,然后将该
    MyClass
    对象缓存为当前作用域的一部分,以便同一作用域内的
    IMyScopedInterface
    后续请求可以接收共享对象
  • 同样的基本流程适用于
    IMyTransientInterface
    ,除了DI系统不需要寻找以前实例化的对象实例,并且在构建新的
    MyClass
    实例之后,它根本不缓存它


    希望从这个流程中可以清楚地看到,
    MyDbContext
    的生存期实际上并不重要。如果它注册为transient,那么
    MyClass
    的每个新实例都将获得它自己的唯一实例
    MyDbContext
    。如果
    MyDbContext
    的生存期是限定范围的(这是实体框架中的默认行为),那么,在给定范围内创建的
    MyClass
    的所有实例都将共享一个
    MyDbContext
    实例,而不管
    MyClass
    实例是为
    IMyScopedInterface
    还是
    IMyTransientInterface

    实例化的,我想您可能在部分问题上弄错了。当说:“…但是如果两者都需要一个DbContext,这意味着我需要创建两个DbContext(是的,一个可以只是一个包装器)并同时注册这两个…”时,这实际上是不正确的。如果您的DbContext注册了一个作用域生命周期(几乎可以肯定是这样),那么只会为当前作用域创建一个DbContext,MyClass的作用域版本和瞬态版本都会在其构造函数中接收它。我接受了答案,尽管它没有回答问题,因为这是对DI的一个很好的解释,它可以帮助其他开发人员,但在我的例子中,很简单,我没有创建一个范围,但是一个依赖关系需要一个范围。。。