在我的自定义ConsoleFormatter
中,我需要从添加到DI的服务中获取一个值。该值保存在SCOPED服务中,因为它为每个新请求生成一个新值,但应该在整个请求过程中保留该值。
问题是,我不知道如何在ConsoleFormatter
中访问DI服务,我在下面尝试的是将services容器放入选项参数中。我的想法是.NET Services是一个单例,这样我就可以在日志记录时请求我的服务并获得我的范围服务。
public static class ConsoleLoggerExtensions
{
public static ILoggingBuilder AddCustomConsoleFormatter(
this ILoggingBuilder builder, Action<CustomConsoleFormatterOptions> options)
{
return builder.AddConsole(
options => options.FormatterName = nameof(CustomLoggingFormatter))
.AddConsoleFormatter<
CustomLoggingFormatter, CustomConsoleFormatterOptions>(
options);
}
}
public sealed class CustomConsoleFormatterOptions : ConsoleFormatterOptions
{
public IServiceProvider serviceProvider { get; set; }
}
public sealed class CustomLoggingFormatter : ConsoleFormatter, IDisposable
{
static long RowIndex = 1;
readonly IDisposable _optionsReloadToken;
CustomConsoleFormatterOptions _formatterOptions;
public CustomLoggingFormatter(
IOptionsMonitor<CustomConsoleFormatterOptions> options)
: base(nameof(SebLoggingFormatter))
{
(_optionsReloadToken, _formatterOptions) =
(options.OnChange(ReloadLoggerOptions), options.CurrentValue);
}
public override void Write<TState>(in LogEntry<TState> logEntry,
IExternalScopeProvider scopeProvider, TextWriter textWriter)
{
string message =
logEntry.Formatter?.Invoke(logEntry.State, logEntry.Exception);
if (message is null)
return;
var idService =
_formatterOptions.serviceProvider.GetService<IIdService>();
var requestId = idService.RequestId;
}
void ReloadLoggerOptions(CustomConsoleFormatterOptions options) =>
_formatterOptions = options;
public void Dispose() =>
_optionsReloadToken?.Dispose();
}
字符串
在启动时,我添加一个任务来获取CustomFormnaytterOptions
services.AddLogging(opt => opt.AddCustomConsoleFormatter(options =>
{
var serviceProvider = services.BuildServiceProvider();
options.serviceProvider = serviceProvider;
}));
型
但是,当我从服务请求IdService时,我会得到一个空值的服务,对我来说,这可能是因为:
- 无http-context(IdService正在根据当前请求中的标头拾取或创建Id)
- 我在这里使用的.net服务是从启动时就存在的,因此与当前请求无关
有一件事我不明白的是,这个选项编码模式(ConsoleOperatorOptions使用)在.net中,似乎是一个内置的功能。我应该以某种方式尝试无效的选项,使它重新运行从启动任务?
1条答案
按热度按时间dsf9zpds1#
您的解决方案存在几个问题,使其无法正常工作:
CustomConsoleFormatterOptions.serviceProvider
字段设置为services.BuildServiceProvider()
将使格式化程序获取所有DI注册的副本。这不会给予您对请求IIdService
的访问权,也不会使您访问活动范围或HTTP请求。BuildServiceProvider
是一个problematic practice,这就是为什么.NET Core中有一个代码分析器会警告你这一点。IServiceProvider
,它将成为“根”服务提供程序,并且不会给予您对作用域服务的访问权限。解决方案是注入
IHttpContextAccessor
类,因为它允许访问当前的HttpContext
:字符串
这可以按如下方式接线:
型