简单注入器:使用ILoggerFactory.CreateLogger注册ILogger ()
我正在使用一个利用Simple Injector作为dependency injection器的项目。 另一方面,该项目使用Microsoft.Extensions.Logging来记录某些类中发生的事件。
我的技术问题很容易解释。 我想在我的DI中注册ILogger独立于正在调用的类T,但是我需要从我的ILoggerFactory.CreateLogger()
方法中执行它,因为它使用Microsoft.Extensions.Configuration
获取记录器配置。
为了实现我的记录器,我需要使用这样的东西:
private Microsoft.Extensions.Logging.ILogger CreateLogger() { var factory = this.ResolveService(); var logger = factory.CreateLogger(); return logger; }
我可以通过以下方式实现注射:
Container.Register(typeof(ILogger), typeof(Logger));
这使我们能够解决以下问题:
public class SomeApiController : ApiController { public SomeApiController(ILogger logger) { //logger is well instantiated, but doesn't got the configuration logger.LogInformation("test log."); } }
但正如我所说,这样做不会通过从Microsoft.Extensions.Logging.ILoggerFactory
类获得的配置,所以这没用。
有没有办法使用我的
CreateLogger
注册ILogger
CreateLogger
?
使用Simple Injector执行此操作的方法是指定将调用委托给ILoggerFactory
的通用代理类。
但是,当使用Microsoft.Extensions.Logging时,这会导致问题,因为它的ILogger
抽象是一个很大的接口隔离原则违规。 ISP违规是有问题的,因为它们使得创建(以及其他)代理类更加困难。 但是,您应该避免在应用程序组件中直接使用该抽象,如依赖性倒置原则所规定的那样。
由于抽象应该由应用程序本身定义,这基本上意味着您需要定义自己的记录器抽象,并在此基础上构建适配器,就像这里描述的那样。 您可以从描述的MicrosoftLoggingAdapter
简单地派生您的通用适配器,如下所示:
public sealed class MicrosoftLoggingAdapter : MicrosoftLoggingAdapter { public MicrosoftLoggingAdapter(ILoggerFactory factory) : base(factory.CreateLogger ()) { } }
使用此通用适配器,您可以按如下方式配置Simple Injector:
container.RegisterSingleton(factory); container.RegisterConditional( typeof(MyApplication.Abstractions.ILogger), c => typeof(MicrosoftLoggingAdapter<>).MakeGenericType(c.Consumer.ImplementationType), Lifestyle.Singleton, c => true);
如果创建自己的抽象不是(还)选项,那么您的第二个最佳选择是使用以下Microsoft.Extensions.Logging特定类来覆盖Simple Injector的dependency injection行为:
class MsContextualLoggerInjectionBehavior : IDependencyInjectionBehavior { private readonly ILoggerFactory factory; private readonly IDependencyInjectionBehavior original; private readonly Container container; public MsContextualLoggerInjectionBehavior( ILoggerFactory factory, Container container) { this.factory = factory; this.original = container.Options.DependencyInjectionBehavior; this.container = container; } public void Verify(InjectionConsumerInfo consumer) => original.Verify(consumer); public InstanceProducer GetInstanceProducer(InjectionConsumerInfo i, bool t) => i.Target.TargetType == typeof(ILogger) ? GetLoggerInstanceProducer(i.ImplementationType) : original.GetInstanceProducer(i, t); private InstanceProducer GetLoggerInstanceProducer(Type type) => Lifestyle.Singleton.CreateProducer(() => factory.CreateLogger(type), container); }
您可以按如下方式替换原始行为:
container.Options.DependencyInjectionBehavior = new MsContextualLoggerInjectionBehavior(loggingFactory, container);
根据史蒂文的解决方案,我发布我的答案来帮助其他人:
private void RegisterServices() { Container.Register(ConfigureLogger, Lifestyle.Singleton); Container.Register(typeof(ILogger<>), typeof(LoggingAdapter<>)); } private ILoggerFactory ConfigureLogger() { LoggerFactory factory = new LoggerFactory(); var config = new ConfigurationBuilder() .AddJsonFile("logging.json") .Build(); //serilog provider configuration var log = new LoggerConfiguration() //.ReadFrom.Configuration(config) .WriteTo .RollingFile(ConfigSettings.LogsPath) .CreateLogger(); factory.AddSerilog(log); return factory; } public class LoggingAdapter : ILogger { private readonly Microsoft.Extensions.Logging.ILogger adaptee; public LoggingAdapter(ILoggerFactory factory) { adaptee = factory.CreateLogger (); } public IDisposable BeginScope(TState state) { return adaptee.BeginScope(state); } public bool IsEnabled(LogLevel logLevel) { return adaptee.IsEnabled(logLevel); } public void Log (LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) { adaptee.Log(logLevel, eventId, state, exception, formatter); } }
如您所见,我的解决方案是使用Serilog作为登录Microsoft.Extensions.Logging
的提供程序。
希望能帮助到你!