【问题标题】:How can I inject dependencies into a custom ILogger in asp.net core 2.0?如何将依赖项注入 asp.net core 2.0 中的自定义 ILogger?
【发布时间】:2017-11-15 05:06:47
【问题描述】:

在 asp.net core 1.1 中,我可以将 IServiceProvider 注入记录器提供程序并在调用 CreateLogger 时解析我的记录器,但在 asp.net core 2.0 中这一切都发生了变化

我的 ILogger 实现需要注入依赖项。 我怎样才能做到这一点?

【问题讨论】:

    标签: c# asp.net-core asp.net-core-2.0


    【解决方案1】:

    ASP.NET 核心提供了用自定义容器替换内置 DI 容器的可能性(有关详细信息,请参阅this 文章)。您可以利用这种可能性来更早地获取 IServiceProvider 的实例以记录引导,同时仍使用标准的 .Net 核心 DI 容器。

    为此,您应该将 Startup.ConfigureServices(IServiceCollection services) 方法的返回值从 void 更改为 IServiceProvider。您可以使用这种可能性在 ConfigureServices 中构建 IServiceProvider 的实例,将其用于记录引导,然后从方法返回。

    示例代码:

    public interface ISomeDependency
    {
    }
    
    public class SomeDependency : ISomeDependency
    {
    }
    
    public class CustomLogger : ILogger
    {
        public CustomLogger(ISomeDependency dependency)
        {
        }
    
        //  ...
    }
    
    public class CustomLoggerProvider : ILoggerProvider
    {
        private readonly IServiceProvider serviceProvider;
    
        public CustomLoggerProvider(IServiceProvider serviceProvider)
        {
            this.serviceProvider = serviceProvider;
        }
    
        public ILogger CreateLogger(string categoryName)
        {
            return serviceProvider.GetRequiredService<ILogger>();
        }
    
        //  ...
    }
    
    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
    
            return ConfigureLogging(services);
        }
    
        private IServiceProvider ConfigureLogging(IServiceCollection services)
        {
            services.AddTransient<ISomeDependency, SomeDependency>();
            services.AddSingleton<ILogger, CustomLogger>();
            IServiceProvider serviceProvider = services.BuildServiceProvider();
    
            var loggerFactory = new LoggerFactory();
            loggerFactory.AddProvider(new CustomLoggerProvider(serviceProvider));
    
            return serviceProvider;
        }
    
        //  ...
    }
    

    【讨论】:

    • 但是我的问题是 ConfigureLogging 在 ConfigureServices 之前被调用,所以依赖项还没有注册。
    • 我指的是 ConfigureLogging 扩展方法,在这里使用docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/…
    • ConfigureLogging() 只是一个辅助扩展方法,它会在适当的时候调用您提供的 lambda。由于您的特定需求,您不能使用 ConfigureLogging,它对您的情况不够灵活。
    • 如果您有一些基本应用程序,这是“可以的”,但这不适用于基于复杂/租户/消息的系统 - 因为就像 Clement 试图说的那样,容器是在 Startup(或 Startup甚至不存在)-您在这里所做的只是传递 ServiceCollection 并手动取回服务...不要误会我的意思..但我认为这不算是依赖注入,因为您没有反转依赖和只是造成了不必要的 Connascence 复杂性。检查我的答案.. 我花了一段时间,但我解决了你的答案!
    【解决方案2】:

    如果您在 program.cs 中配置日志记录,您可以创建一个函数来配置日志记录并获取日志记录提供程序的实例,如下所示:

    private static void ConfigureApplicationLogging(WebHostBuilderContext context, ILoggingBuilder loggingBuilder)
        {
            loggingBuilder.AddConfiguration(context.Configuration.GetSection("Logging"));
            loggingBuilder.AddDebug();
            loggingBuilder.AddConsole();
    
            var serviceProvider = loggingBuilder.Services.BuildServiceProvider();
            loggingBuilder.AddProvider(new DoxErrorLoggerProvider(serviceProvider, null));
        }
    

    然后在 BuildWebHost 中配置日志记录如下:

            public static IWebHost BuildWebHost(string[] args) =>            
            WebHost.CreateDefaultBuilder(args)
                .ConfigureLogging(ConfigureApplicationLogging)
                .UseNLog()
                .UseStartup<Startup>()
                .Build();
    

    【讨论】:

      【解决方案3】:

      从你在各个地方需要的依赖项开始

      public class SomeDependency : ISomeDependency
      {
      }
      

      一个扩展文件,以便我们可以根据 MSDN 在 ServiceCollection 上配置日志记录 您可以在各种来源中找到非常标准的东西

      public static class ApplicationLoggerFactoryExtensions
      {
          public static ILoggingBuilder CustomLogger(this ILoggingBuilder builder)
          {
              builder.Services.AddSingleton<ILoggerProvider, CustomLoggerProvider>();
              //Be careful here. Singleton may not be OK for multi tenant applications - You can try and use Transient instead.
              return builder;
          }
      }
      

      记录器提供程序是在您处理业务代码并需要记录内容时被称为之后服务的部分。

      因此,在应用程序的上下文中,DI 是在此处构建并可用的。现在为什么 ILoggerProvider 存在可能是有道理的。

      public class CustomLoggerProvider : ILoggerProvider
      {
          private ISomeDependency someDependency;
      
          public CustomLoggerProvider(ISomeDependency someDependency)
          {
              this.someDependency = someDependency;
          }
      
          public ILogger CreateLogger(string categoryName)
          {
              return new CustomeLogger(someDependency);
          }
      }
      

      具体的自定义记录器非常简单

      public class CustomLogger : ILogger
      {
          public CustomLogger(ISomeDependency dependency)
          {
          }
      }
      

      在您配置 ServiceCollection 的地方.. 就像在 Startup.cs 中的 OP 问题中一样

      private void ConfigureServices(IServiceCollection services)
      {
          services.AddTransient<ISomeDependency, SomeDependency>();
      
          //services.AddSingleton<ILogger, CustomLogger>(); <== NO
      
          var loggerFactory = new LoggerFactory(); //??? newer DotNet gives you LoggerFactory in startup this may be unnecessary.
      
         //Add some console printer
         services.AddLogging(configure => configure.AddConsole())
                     .Configure<LoggerFilterOptions>(options => options.MinLevel = LogLevel.Trace);
      
          //Add our custom logger
          services.AddLogging(configure => configure.CustomLogger()); // <== our extension helping out!
      }
      

      所以只是说明一下ILogger的使用

      ✘ 不要 - 不要将任何 ILogger 添加到您的服务中

      LoggerFactoryLoggerProvider 配置的全部意义在于简化ILogger 的使用

      public MyBusinessService(ILogger<BusinessServiceClass> log)
      {
        log.Information("Please tell all registered loggers I am logging!);
      }
      

      在我的示例中,它将向控制台打印出消息(如果可用)以及采用我们注入的依赖项的 CustomLogger。如果您注册更多..它将转到所有人

      【讨论】:

        猜你喜欢
        • 2018-08-08
        • 1970-01-01
        • 2023-03-12
        • 2018-03-23
        • 1970-01-01
        • 2018-10-17
        • 1970-01-01
        • 2016-09-13
        • 1970-01-01
        相关资源
        最近更新 更多