在.Net Core 2.2应用程序中,我需要一个服务版本(作为瞬态)和一个范围界定的版本。
对于“常规”服务,我可以创建两个不同的接口,将一个注册为临时接口,将一个注册为作用域接口,但是如果两者都需要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
,我如何要求瞬态分辨率与范围分辨率?
答案 0 :(得分:1)
最简单的方法是使用两个接口,如以下示例所示:
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>();
您不需要对DbContext
做任何特别的事情来支持这一点。让我们来看一下DI系统如何解决这些服务,以查看它是否可以弄清为什么。
IMyScopedInterface
的实例(通常是因为DI系统试图实例化其构造函数采用IMyScopedInterface
参数的其他服务)。IMyScopedInterface
已在作用域生存期内进行了注册,因此DI系统首先在其已为当前作用域实例化的服务集合中查找其是否已经创建了IMyScopedInterface
。该搜索空手而归,因此DI系统将继续创建MyClass
的新实例。MyClass
的构造函数并确定它需要一个MyDbContext
,因此它通过相同的流程递归以获取MyDbContext
。MyClass
的{{1}}实例,然后将该MyDbContext
对象作为当前范围的一部分进行缓存,以便后续对MyClass
的请求同一范围内的用户可以接收共享对象。 IMyScopedInterface
的基本流程相同,除了DI系统不会费心寻找对象的先前实例化实例,并且在构造新的IMyTransientInterface
实例之后,它不会缓存一切。
从此流程中应该希望清楚的是,MyClass
的生存期实际上并不重要。如果将其注册为瞬态,则MyDbContext
的每个新实例都将获得其自己的MyClass
唯一实例。如果MyDbContext
的生存期是有作用域的(这是Entity Framework中的默认行为),则在给定范围内创建的MyDbContext
的所有实例将共享一个MyClass
的实例已为MyDbContext
或MyClass
实例化了IMyScopedInterface
个实例。