RegisterWithContext 与生活方式不匹配

RegisterWithContext and Lifestyle Mismatch

我想向我的控制器中注入一个记录器,我需要将扩展​​信息传递给记录器的构造函数。为此,我使用 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

我需要在恰好是单例的服务中注入相同的记录器 (Common.Logging.NLogLogger)。

在升级到 SimpleInjector 3.0.6 之前,一切似乎都按预期工作,container.Verify() 对整个配置非常满意。

验证器升级后returns一些错误:

[Lifestyle Mismatch] SearchEngineIndexerService (Singleton) depends on ILogger (Transient). [Lifestyle Mismatch] MembershipService (Web Request) depends on ILogger (Transient).

这是有道理的。我能理解为什么会发生这种情况以及为什么应该避免这种情况。

我正在努力避免 "Do I log too much" 综合症,但实际上,我确实需要登录一些服务。

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

Type ILogger has already been registered as unconditional registration. For non-generic types, conditional and unconditional registrations can't be mixed.

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

您现在看到此异常的原因是因为 v3.0.6 修复了 some bugs 阻止生活方式不匹配警告在某些情况下出现。

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

因此,最好定义一个代理记录器 class 允许将调用转发给真正的记录器。例如:

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);

documentation对此进行了更详细的描述。