RegisterWithContext和Lifestyle Mismatch
我想向我的控制器注入一个记录器,我需要将扩展信息传递给记录器的构造函数。 为此,我使用RegisterWithContext
:
container.RegisterWithContext(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()
对整个配置非常满意。
升级后,validation程序返回一些错误:
[Lifestyle Mismatch] SearchEngineIndexerService(Singleton)依赖于ILogger(Transient)。 [Lifestyle Mismatch] MembershipService(Web Request)取决于ILogger(Transient)。
这是有道理的。 我能理解为什么会发生这种情况以及为什么要避免它。
我试图避免“我是否记录太多”综合症,但实际上,我确实需要在一些服务中进行一些记录。
我已经尝试使用RegisterConditional根据某些条件注册一个不同的记录器,但是,当然,所有记录器现在应该是有条件注册的,否则我会得到这个exception:
类型ILogger已经注册为无条件注册。 对于非generics类型,有条件和无条件注册不能混合使用。
将记录器注册为控制器的瞬态和另一个用于单件服务的最佳方法是什么?
你现在看到这个例外的原因是因为v3.0.6修复了一些阻止生活方式不匹配警告在某些情况下出现的错误。
最好忽略RegisterWithContext
扩展方法,因为它已被v3中的RegisterConditional
方法取代。 但是, RegisterConditional
只允许注册类型; 不是委托,因为委托允许您根据运行时决策做出决策,但在对象图解析期间做出运行时决策是不好的做法。
因此,最好定义一个代理记录器类,允许将调用转发给真正的记录器。 例如:
public sealed class Logger : 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);
文档更详细地描述了这一点。