Asp.net web api 简单注入器:寄存器条件vs寄存器单体

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

上下文:我试图使用serilog和弹性搜索接收器捕获api中的多个事件,这些事件包括:获取操作(常规web api流)以及登录尝试(Owin)。 我是这样注册serilog的:

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)