【问题标题】:How to pass dependencies to a custom .NET Core ILoggerProvider如何将依赖项传递给自定义 .NET Core ILoggerProvider
【发布时间】:2018-12-02 03:21:40
【问题描述】:

我正在创建一个自定义 .NET Core ILoggerProvider,它需要将一些依赖项传递到其构造函数中。

我相信我正在使用一种相当常见的模式来初始化我的日志记录实现;它看起来像这样:

var services = new ServiceCollection();

// Register some services here

services.AddLogging(builder =>
{
    builder.AddProvider(new DebugLoggerProvider());
});

var provider = services.BuildServiceProvider();

我想在 AddLogging 块中添加我的新提供程序,就像当前添加 DebugLoggerProvider 一样。

我的自定义提供程序需要将一些其他服务传递到其构造函数中,并且由于这些服务已经在ServiceCollection 中注册,我假设我应该能够引用它们。但是,与 AddSingleton 等方法不同,这些方法具有暴露 IServiceProvider 的重载,AddLogging 似乎没有提供等效项。

有没有一种简单的方法来实现这一点,或者我是否试图做一些与 .NET Core 日志记录的设计方式相矛盾的事情?

更新:

在尝试了@Nkosi 提出的建议后,我可以确认可以通过绕过AddLogging 并直接在内部实现它的功能来使其工作,如下所示:

var services = new ServiceCollection();

// Register some services
services.AddSingleton<IMyService, MyService>();

// Initialize logging
services.AddOptions();
services.AddSingleton<ILoggerFactory, LoggerFactory>();
services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
services.AddSingleton<ILoggerProvider>(p => new DebugLoggerProvider());
services.AddSingleton<ILoggerProvider>(p => new MyLoggerProvider("Constant value", p.GetService<IMyService>()));

var provider = services.BuildServiceProvider();

【问题讨论】:

    标签: c# logging dependency-injection .net-core .net-core-2.0


    【解决方案1】:

    现在我不确定是否已经存在可以执行此操作的扩展程序,但我在这里看到了潜力。

    首先这是AddProvider 在源代码仓库中的定义方式。

    public static ILoggingBuilder AddProvider(this ILoggingBuilder builder, ILoggerProvider provider) {
        builder.Services.AddSingleton(provider);
        return builder;
    }
    

    您可以在此基础上制作自己的通用版本

    public static class MyLoggingBuilderExtensions {
        public static ILoggingBuilder AddProvider<T>(this ILoggingBuilder builder)
            where T: class, ILoggerProvider{
            builder.Services.AddSingleton<ILoggerProvider, T>();
            return builder;
        }
    }
    

    这应该允许 DI 容器在解析时构建对象图

    services.AddLogging(builder =>
    {
        builder.AddProvider<CustomLoggerProvider>();
    });
    

    还有扩展此功能的空间,例如添加您自己的重载以公开 IServiceProvider 并将其传递给扩展中的 AddSingleton

    public static ILoggingBuilder AddProvider<T>(this ILoggingBuilder builder, Func<IServiceProvider, T> factory)
        where T: class, ILoggerProvider {
        builder.Services.AddSingleton<ILoggerProvider, T>(factory);
        return builder;
    }
    

    使用过

    services.AddLogging(builder => {
        builder.AddProvider<CustomLoggerProvider>(p => new CustomLoggerProvider("Constant value", p.GetService<IMyService>()));
    });
    

    【讨论】:

    • 这是一个天才的解决方案 - 谢谢 :) 正如你所说,这似乎是应该已经存在的东西,但是假设它不乐意将你的扩展应用到我的代码库中。
    • 经过测试,我发现它并没有完全按照我的预期工作。如果我的自定义提供程序有一个无参数的构造函数,它就可以工作。但是,一旦我引入了需要注入的依赖项,它就会在尝试解决它们时失败。这可能是因为 ILoggingBuilder 使用的 IServiceCollection 与主 DI ServiceCollection 是分开的吗?
    • 有可能。尝试注册其他依赖项,看看它是否有效。那将证明这一点。
    • 不幸的是,似乎唯一可行的方法是在将提供程序添加到日志记录构建器之前解析整个依赖链(即创建所有依赖项的实例)。我尝试在 AddLogging 中复制所有依赖项(及其依赖项)的 DI 定义(这也很丑陋),但仍然失败。这个日志记录实现似乎有一个大漏洞。
    • @TimCoulter 这很奇怪,因为在 repo 中进一步调查我可以看到它正在使用相同的服务集合github.com/aspnet/Logging/blob/dev/src/…
    【解决方案2】:

    很抱歉在这个派对上迟到了一点,但我在高低搜索后遇到了完全相同的问题。受此页面中优秀条目的启发,我最终得到了以下解决方案。

    services.AddTransient<IMyLogRepository, LogRepository>();
    var loggerFactory = LoggerFactory.Create(builder =>
            {
                builder.AddConsole()
                       .AddDbLoggerProvider(services.BuildServiceProvider().GetService<IMyLogRepository>());
            });
            services.AddSingleton(loggerFactory.CreateLogger("MyLogging"));
    

    这个存在的关键:

    services.BuildServiceProvider().GetService<IMyLogRepository>())
    

    这允许我将我的数据库存储库链接到我在一个额外的行中创建的 dbLogger 对象。从本质上讲,它使我能够提取我的 DI 数据库对象并通过标准的 ILoggerProviderILogger 接口将其发送到日志服务

    【讨论】:

      【解决方案3】:

      我有一个简单的工作解决方案,它有点轻。

      serviceCollection.AddLogging(logBuilder =>
      {
          logBuilder.AddConfiguration(theConfigRoot.GetSection("Logging"));
      });
      serviceCollection.AddSingleton<ILoggerProvider, MyLogProvider>();
      

      但是.... 实例化提供程序可以防止您在循环依赖问题中运行--> 您可能希望很快注入的服务本身就是一个记录器^^

      【讨论】:

        猜你喜欢
        • 2017-07-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-26
        • 1970-01-01
        • 2016-10-08
        • 2017-01-09
        • 2020-01-30
        相关资源
        最近更新 更多