注册具有多个生命周期的服务
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 系统如何解析这些服务,看看它是否能阐明为什么会这样。
- 首先,DI 系统尝试获取
IMyScopedInterface
的实例(通常是因为 DI 系统试图实例化一些其他服务,其构造函数采用 IMyScopedInterface
参数)。
- 因为
IMyScopedInterface
已经注册了范围生命周期,DI 系统首先在它的服务集合中查找已经为当前范围实例化的服务,看看它是否已经创建了一个 IMyScopedInterface
.该搜索空手而归,因此 DI 系统随后继续创建 MyClass
. 的新实例
- 为此,它检查
MyClass
的构造函数并确定它需要一个 MyDbContext
,因此它通过相同的流程递归以获得 MyDbContext
。
- DI系统构造一个
MyClass
的实例提供获得的MyDbContext
,然后将这个MyClass
对象缓存为当前作用域的一部分,以便后续对[=13]的请求=] 同一范围内可以接收共享对象。
相同的基本流程适用于 IMyTransientInterface
,除了 DI 系统不会费心寻找对象的先前实例化实例,并且在构建新的 MyClass
实例后它不会'根本不缓存它。
从这个流程中应该清楚的是,MyDbContext
的生命周期有多长并不重要。如果它被注册为瞬态,那么 MyClass
的每个新实例都将获得它自己唯一的 MyDbContext
实例。如果 MyDbContext
的生命周期是限定范围的(这是 Entity Framework 中的默认行为),那么在给定范围内创建的所有 MyClass
实例将共享 MyDbContext
的单个实例不管 MyClass
实例是为 IMyScopedInterface
还是 IMyTransientInterface
.
实例化的
在 .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 系统如何解析这些服务,看看它是否能阐明为什么会这样。
- 首先,DI 系统尝试获取
IMyScopedInterface
的实例(通常是因为 DI 系统试图实例化一些其他服务,其构造函数采用IMyScopedInterface
参数)。 - 因为
IMyScopedInterface
已经注册了范围生命周期,DI 系统首先在它的服务集合中查找已经为当前范围实例化的服务,看看它是否已经创建了一个IMyScopedInterface
.该搜索空手而归,因此 DI 系统随后继续创建MyClass
. 的新实例
- 为此,它检查
MyClass
的构造函数并确定它需要一个MyDbContext
,因此它通过相同的流程递归以获得MyDbContext
。 - DI系统构造一个
MyClass
的实例提供获得的MyDbContext
,然后将这个MyClass
对象缓存为当前作用域的一部分,以便后续对[=13]的请求=] 同一范围内可以接收共享对象。
相同的基本流程适用于 IMyTransientInterface
,除了 DI 系统不会费心寻找对象的先前实例化实例,并且在构建新的 MyClass
实例后它不会'根本不缓存它。
从这个流程中应该清楚的是,MyDbContext
的生命周期有多长并不重要。如果它被注册为瞬态,那么 MyClass
的每个新实例都将获得它自己唯一的 MyDbContext
实例。如果 MyDbContext
的生命周期是限定范围的(这是 Entity Framework 中的默认行为),那么在给定范围内创建的所有 MyClass
实例将共享 MyDbContext
的单个实例不管 MyClass
实例是为 IMyScopedInterface
还是 IMyTransientInterface
.