简单注入器:使用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的提供程序。

希望能帮助到你!