如何将依赖项传递给自定义 .NET Core ILoggerProvider
How to pass dependencies to a custom .NET Core ILoggerProvider
我正在创建一个自定义 .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();
现在我不确定是否已经存在执行此操作的扩展程序,但我在这里看到了潜力。
首先,这是 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>())
这让我可以 link 我的数据库存储库到我在一个额外的行中创建的 dbLogger 对象。本质上,它使我能够提取我的 DI 数据库对象并通过标准 ILoggerProvider
和 ILogger
接口将其发送到日志记录服务
我有一个简单的工作解决方案,它有点轻。
serviceCollection.AddLogging(logBuilder =>
{
logBuilder.AddConfiguration(theConfigRoot.GetSection("Logging"));
});
serviceCollection.AddSingleton<ILoggerProvider, MyLogProvider>();
但是...。实例化提供者可以避免 运行 循环依赖问题 --> 您可能希望很快注入的服务本身需要一个记录器^^
我正在创建一个自定义 .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();
现在我不确定是否已经存在执行此操作的扩展程序,但我在这里看到了潜力。
首先,这是 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>())
这让我可以 link 我的数据库存储库到我在一个额外的行中创建的 dbLogger 对象。本质上,它使我能够提取我的 DI 数据库对象并通过标准 ILoggerProvider
和 ILogger
接口将其发送到日志记录服务
我有一个简单的工作解决方案,它有点轻。
serviceCollection.AddLogging(logBuilder =>
{
logBuilder.AddConfiguration(theConfigRoot.GetSection("Logging"));
});
serviceCollection.AddSingleton<ILoggerProvider, MyLogProvider>();
但是...。实例化提供者可以避免 运行 循环依赖问题 --> 您可能希望很快注入的服务本身需要一个记录器^^