如何将依赖项注入 asp.net core 2.0 中的自定义 ILogger?

How can I inject dependencies into a custom ILogger in asp.net core 2.0?

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

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

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

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

示例代码:

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

    //  ...
}

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

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

记录器提供程序是被调用的部分 AFTER 当您在业务代码中工作并需要记录内容时构建服务。

因此,在应用程序的上下文中,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 接受了我们注入的依赖项。如果你注册更多..它会去所有的人

如果您在 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();