如何将依赖项传递给自定义 .NET Core ILoggerProvider



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

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

var services = new ServiceCollection();
// Register some services here
services.AddLogging(builder =>
{
builder.AddProvider(new DebugLoggerProvider());
});
var provider = services.BuildServiceProvider();

我想在AddLogging块中添加我的新提供程序,其方式与当前添加DebugLoggerProvider的方式相同。

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

是否有一种简单的方法可以实现此目的,或者我是否尝试执行与 .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();

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

首先,这是在源代码存储库中定义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>()));
});

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

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接口将其发送到日志记录服务

我得到了一个简单的工作解决方案,它更轻。

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

然而。。。。实例化提供程序可以防止您在循环依赖问题中运行 ->您可能想要很快注入的服务是记录器本身^^

最新更新