注册具有多个生命周期的服务

Register service with multiple lifetime

在 .Net Core 2.2 应用程序中,我需要一个服务版本作为瞬态,一个版本作为作用域。

对于 "regular" 服务,我可以创建两个不同的接口,将一个注册为瞬态接口,一个注册为作用域,但如果两者都需要 DbContext,则意味着我需要创建两个 DbContext(是的,一个可以只是一个包装器)并注册两者,但它感觉不合适。

我使用的是 dotnet Core 的默认依赖注入框架,我不太熟悉它。在 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());
}

奖励积分:使用 IServiceProvider,我如何请求瞬态分辨率与范围分辨率?

最简单的实现方式是使用两个接口,如下例所示:

interface IMyScopedInterface
{
    void Foo();
}

interface IMyTransientInterface
{
    void Foo();
}

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

    public void Foo()
    {
    }
}

然后使用以下方式注册您的 class:

services.AddTransient<IMyTransientInterface, MyClass>();
services.AddScoped<IMyScopedInterface, MyClass>();

您不需要对您的 DbContext 做任何特殊的事情来支持它。让我们来看看 DI 系统如何解析这些服务,看看它是否能阐明为什么会这样。

  1. 首先,DI 系统尝试获取 IMyScopedInterface 的实例(通常是因为 DI 系统试图实例化一些其他服务,其构造函数采用 IMyScopedInterface 参数)。
  2. 因为 IMyScopedInterface 已经注册了范围生命周期,DI 系统首先在它的服务集合中查找已经为当前范围实例化的服务,看看它是否已经创建了一个 IMyScopedInterface.该搜索空手而归,因此 DI 系统随后继续创建 MyClass.
  3. 的新实例
  4. 为此,它检查 MyClass 的构造函数并确定它需要一个 MyDbContext,因此它通过相同的流程递归以获得 MyDbContext
  5. DI系统构造一个MyClass的实例提供获得的MyDbContext,然后将这个MyClass对象缓存为当前作用域的一部分,以便后续对[=13]的请求=] 同一范围内可以接收共享对象。

相同的基本流程适用于 IMyTransientInterface,除了 DI 系统不会费心寻找对象的先前实例化实例,并且在构建新的 MyClass 实例后它不会'根本不缓存它。

从这个流程中应该清楚的是,MyDbContext 的生命周期有多长并不重要。如果它被注册为瞬态,那么 MyClass 的每个新实例都将获得它自己唯一的 MyDbContext 实例。如果 MyDbContext 的生命周期是限定范围的(这是 Entity Framework 中的默认行为),那么在给定范围内创建的所有 MyClass 实例将共享 MyDbContext 的单个实例不管 MyClass 实例是为 IMyScopedInterface 还是 IMyTransientInterface.

实例化的