RegisterWithContext和生活方式不匹配

本文关键字:不匹配 生活方式 RegisterWithContext | 更新日期: 2023-09-27 18:16:10

我想注入一个记录器到我的控制器,我需要将扩展信息传递给记录器的构造函数。为此,我使用了RegisterWithContext:

container.RegisterWithContext<Common.Logging.ILogger>(context =>
{
    if (context.ServiceType == null && !container.IsVerifying())
        {
        throw new InvalidOperationException(
            "Can't request ILogger directly from container, " + 
            "it must be injected as a dependency.");
    }
    return new Common.Logging.NLogLogger(context.ImplementationType.FullName);
});

RegisterWithContext扩展方法显式将提供的委托注册为Transient

我需要在一个碰巧是单例的服务中注入相同的Logger (Common.Logging.NLogLogger)。

在升级到SimpleInjector 3.0.6之前,事情似乎如预期的那样工作,container.Verify()对整个配置非常满意。

升级后校验器返回一些错误:

[Lifestyle Mismatch] SearchEngineIndexerService (Singleton)取决于ILogger实例(瞬态)。[生活方式不匹配]会员服务(Web请求)依赖于ILogger (Transient)。

,这是有意义的。我能理解为什么会发生这种情况,为什么应该避免。

我试图避免"我是否记录了太多"综合症,但是,实际上,我真的需要在几个服务中做一些记录。

我已经尝试使用RegisterConditional根据某些条件注册一个不同的记录器,但是,当然,现在所有的记录器都应该是有条件注册的,否则我会得到这个异常:

类型ILogger已被注册为无条件注册。对于非泛型类型,不能混合使用条件注册和无条件注册。

将一个记录器注册为控制器的暂态记录器,而将另一个记录器注册为单例服务的最佳方法是什么?

RegisterWithContext和生活方式不匹配

您现在看到这个异常的原因是v3.0.6修复了一些在某些情况下阻止生活方式不匹配警告显示的错误。

最好忽略RegisterWithContext扩展方法,因为它在v3中已经被RegisterConditional方法所取代。然而,RegisterConditional只允许注册类型;不是委托,因为委托允许您基于运行时决策做出决策,但是在对象图解析期间做出运行时决策是不好的实践。

因此,最好定义一个代理记录器类,允许将调用转发给真正的记录器。例如:
public sealed class Logger<T> : ILogger
{
    private static readonly ILogger logger = 
        new Common.Logging.NLogLogger(typeof(T).FullName);
    // Implement ILogger methods here
    void ILogger.Log(string message) {
        // Delegate to real logger
        logger.Log(message);
    }
}

这个实现可以注册如下:

container.RegisterConditional(typeof(ILogger),
    c => typeof(Logger<>).MakeGenericType(c.Consumer.ImplementationType),
    Lifestyle.Singleton,
    c => true);

文档对此有更详细的描述。