每个 Web 请求和上下文的简单注入器注册
-
23-12-2019 - |
题
有 RegisterPerWebRequest
和 RegisterWithContext
(这个最初并没有附带简单的注射器,但是它是在他们的 高级场景部分)。两种方法单独工作都很好,但我需要将它们结合起来。
我发现在 RegisterPerWebRequest
用过的 new WebRequestLifestyle()
生活方式(找到了 那里)。所以不要使用 Lifestyle.Transient
RegisterWithContext
我提供了 new WebRequestLifestyle()
但看来 DependencyContext.ImplementationType
和 DependencyContext.ServiceType
为空。
这有什么问题吗?
更新1。
所以我想按照网络请求注册类型 RegisterPerWebRequest
而且还能够为实例创建者提供对注入注册类型的类型的访问权限。
我修改了(提取生活方式作为参数) RegisterWithContext
成为:
public static void RegisterWithContext<TService>(
this Container container,
Func<DependencyContext, TService> contextBasedFactory, Lifestyle lifestyle)
where TService : class
{
//original code
container.Register<TService>(rootFactory, lifestyle);
//original code
}
对于“每个网络请求和上下文”注册,我希望能够使用:
container.RegisterWithContext<IUnitOfWork>(dependencyContext =>
{
var implementationType = dependencyContext.ImplementationType;
//do some stuff and return preconfigured UnitOfWork
}, new WebRequestLifestyle());
正如我已经提到的 dependencyContext.ImplementationType
是 NULL
我正在使用 SimpleInjector 2.3.0.0
解决方案
这 RegisterWithContext
扩展方法显式地将提供的委托注册为 Transient
. 。这样做是因为用任何其他生活方式注册该类型没有什么意义。
生活方式的想法,例如 WebRequestLifestyle
是在整个对象图中缓存并重用相同的实例(可能还不止于此)。然而,这个概念在处理基于上下文的注册时没有什么意义,因为基于上下文的实例每次注入时都应该是不同的。换句话说,为每个消费者提供唯一的实例与重用同一实例的概念相冲突。
例如,看一下下面的对象图:
new HomeController(
new Logger("HomeController"),
new LoggingRepositoryDecorator<User>(
new Logger("LoggingRepositoryDecorator<User>"),
new SqlRepository<User>(
new DbContext())),
new LoggingCommandHandlerDecorator<ShipOrder>(
new Logger("LoggingCommandHandlerDecorator<ShipOrder>"),
new ShipOrderCommandHandler(
new DbContext())));
在此对象图中,我们创建一个 HomeController
及其依赖项。这 Logger
组件显然是一个基于上下文的组件,因为它每次都会根据其父级进行不同的初始化。这将是注册 Logger
:
container.RegisterWithContext<ILogger>(context =>
new Logger(context.ImplementationType.Name));
但如果我们允许 ILogger
注册 注册到 WebRequestLifestyle
, ,每次都应该应用相同的实例,这可能会导致以下对象图:
ILogger logger = new Logger(typeName: "HomeController");
new HomeController(
logger,
new LoggingRepositoryDecorator<User>(
logger,
new SqlRepository<User>(
new DbContext())),
new LoggingCommandHandlerDecorator<ShipOrder>(
logger,
new ShipOrderCommandHandler(
new DbContext())));
在此对象图中相同 Logger("HomeController")
被注入了,这显然不是我们想要的。此外,行为变得非常不可预测,因为首先创建的是消费者,这将决定记录器的 typeName
在整个图表中被重复使用。但没有人会想到删除 ILogger
来自 HomeController
的构造函数,会导致记录器 LoggingCommandHandlerDecorator<ShipOrder>
改变。
这就是为什么没有 Lifestyle
论据中的 RegisterWithContext
扩展方法。