Asp.net web api 简单注入器:寄存器条件vs寄存器单体
上下文:我试图使用serilog和弹性搜索接收器捕获api中的多个事件,这些事件包括:获取操作(常规web api流)以及登录尝试(Owin)。 我是这样注册serilog的:Asp.net web api 简单注入器:寄存器条件vs寄存器单体,asp.net-web-api,serilog,simple-injector,Asp.net Web Api,Serilog,Simple Injector,上下文:我试图使用serilog和弹性搜索接收器捕获api中的多个事件,这些事件包括:获取操作(常规web api流)以及登录尝试(Owin)。 我是这样注册serilog的: container.RegisterConditional( typeof(ICustomLogger), c => typeof(CustomLogger<>).MakeGenericType( c.Consumer?.ImplementationType ?? typ
container.RegisterConditional(
typeof(ICustomLogger),
c => typeof(CustomLogger<>).MakeGenericType(
c.Consumer?.ImplementationType ?? typeof(object)),
Lifestyle.Singleton,
c => true);
然后当我调用container.Verify()时代码>将调用记录器构造函数(如预期)。
但是,当我从我的OAuthAuthorizationServerProvider
实现调用记录器时,如下所示:
var logger=ObjectFactory.GetInstance()代码>再次调用构造函数,这意味着单例不再是真正的单例,我完全知道服务定位器反模式(现在没有太多时间重构该部分),有趣的是,如果我将记录器注册更改为以下内容(去掉类型部分)然后只创建一个实例:
container.RegisterSingleton(typeof(ICustomLogger), typeof(CustomLogger))
我之所以尝试使用第一个选项,是因为我希望能够使用.ForContext(typeof(T))
用于serilog,如果您想知道我是如何注册ObjectFactory
的,那么它就是:
类别:
所以我的主要问题是:为什么只有一个实例是用RegisterSingleton
创建的,而多个实例是用RegisterConditional
和生活方式创建的。Singleton
?创建多个实例的原因与您正在使用对象工厂这一事实无关,但这仅仅是因为创建了不同的CustomLogger
封闭版本:
- 解析为根类型时(通过调用
GetInstance()
- 将
ICustomLogger
注入Service1
时,将创建CustomLogger
因为<代码> CustomLogger <代码>是与<代码> CustomLogger < /C> >不同的类型,不可能只有两个类型的一个实例。它们都必须被创建。这可能看起来很奇怪,但请考虑这两个类:
公共类服务1
{
公共服务1(ICustomLogger){}
}
公共类服务2
{
公共服务2(ICustomLogger){}
}
在运行时,考虑到这两个定义,您希望创建类似以下内容的对象图:
var s1=new Service1(new CustomLogger());
var s2=new Service2(new CustomLogger());
在上述情况下,CustomLogger
s不会被缓存,因此是有效的瞬态。您可以尝试将其重写为以下内容,但情况不同:
ICustomLogger=new CustomLogger();
var s1=新服务1(记录器);
var s2=新服务2(记录器);
现在,两个服务都获得相同的单个实例。但是,这意味着Service2
获得的CustomLogger
不是您配置的。您将依赖项配置为:
typeof(CustomLogger<>).MakeGenericType(c.Consumer.ImplementationType)
这两种情况下,可以创建多个封闭的通用版本:代码> Foo和 FooWooTalks>代码>,但是简单的注入器保证了每个代码的一个实例:“代码> Foo”。/p>
container.Collection.Append(lifety.Singleton);
容器。收集。附加(生活方式。单身);
容器。注册Decorator(生活方式。单身);
在这种情况下,将注册ILogger
组件的集合,其中每个ILogger
元素将使用LoggerDecorator
进行包装。因为LoggerDecorator
只能依赖于Logger1
或Logger2
,但不能同时依赖于两者,所以简单的注入器必须创建一个新的LoggerDecorator
每个元素的实例。如果将LoggerDecorator
缓存为真正的单例,则结果如下:
private static ILogger logger=new LoggerDecorator(new Logger1());
私有静态记录器=新[]{logger,logger};
由于只有一个LoggerDecorator
,此decorator依赖于Logger1
,这意味着记录器集合只有两个元素,它们都指向相同的Logger1
实例。没有Logger2
该信息反映在以下简单喷油器文档章节中:
Hi@Steven,感谢您的及时响应和出色的回答,这澄清了一切。我想我将不得不放弃捕获调用方上下文,因为我的记录器上有一个文件接收器作为后备,多个实例在尝试写入文件时都会导致问题(这实际上是我发现创建多个实例的方式)。感谢您的帮助!
public static class ObjectFactory
{
public static Container container;
public static void SetContainer(Container container)
{
ObjectFactory.container = container;
}
public static T GetInstance<T>() where T : class
{
return container.GetInstance<T>();
}
}
ObjectFactory.SetContainer(container);
typeof(CustomLogger<>).MakeGenericType(c.Consumer.ImplementationType)