Logger在Startup和ConfigureServices之间被处理



我创建了一个记录器,它应该记录应用程序运行开始时的任何内容。我想让它在StartupConfigureServices之间保持不变。我将其存储在类似于configuration

的属性中代码


public Startup(IConfiguration configuration)
{
Configuration = configuration;
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.SetMinimumLevel(LogLevel.Error);
builder.AddEventLog(s =>
{
s.LogName = "MyLogName";
s.SourceName = "MySource";
});
// add some other persisting logger
});
StartupLogger = loggerFactory.CreateLogger<Startup>();
}
public IConfiguration Configuration { get; }
public ILogger StartupLogger { get; } // Logger exists here when breakpoint is in ConfigureServices
public void ConfigureServices(IServiceCollection services)
{

StartupLogger.LogError("Failed to do something"); // <-- throws exception
}

是我得到的错误。看起来内部日志记录器在进程

中被处理掉了

消息:"写入记录器时发生错误。无法访问已处置的对象。对象名称:'EventLogInternal'.

完整的堆栈

'StartupLogger.LogError("Failed to do something")'抛出类型为'System '的异常。AggregateException '
数据:{System.Collections。ListDictionaryInternal}
HResult: -2146233088
helpink: null
InnerException: {"无法访问已处置的对象。rnObject name: 'EventLogInternal'."}
InnerExceptions: Count = 1
消息:"写入记录器时发生错误。无法访问已处置的对象。rnObject name: 'EventLogInternal'.)">
来源:" microsoft . extensions . loging& quot;
StackTrace: "在Microsoft.Extensions.Logging.Logger。rn at microsoft . extension . logging . logger . log [TState](LogLevel LogLevel, EventId EventId, TState状态,Exception Exception, Func ' 3 formatter)rn at microsoft . extension . logging . logger ' 1. microsoft . extension . logging . log . log [TState](LogLevel LogLevel, EventId EventId, TState状态,Exception Exception, Func ' 3 formatter)rn at microsoft . extension . logging . loggerextensions log (ILogger logger, LogLevel LogLevel, EventId EventId, EventId EventId, Exception Exception, Exception Exception,字符串消息,Object[] args)rn at Microsoft.Extensions.Logging.LoggerExtensions。LogError(ILogger logger, String message, Object[] args)">
TargetSite:{无效ThrowLoggingError(System.Collections.Generic.List ' 1[System.Exception])}

我肯定用错方法了。谢谢你的指导。

将using声明using var loggerFactory更改为普通声明-这会导致在作用域结束时处置loggerFactory(在本例中为Startup构造函数):

public Startup(IConfiguration configuration)
{
Configuration = configuration;
var loggerFactory = LoggerFactory.Create(builder =>
{
builder.SetMinimumLevel(LogLevel.Error);
builder.AddEventLog(s =>
{
s.LogName = "MyLogName";
s.SourceName = "MySource";
});
// add some other persisting logger
});
StartupLogger = loggerFactory.CreateLogger<Startup>();
}

还请注意,StartupConfigure方法支持依赖注入,如果您可以将初始化逻辑移到那里-您可以将ILogger<Startup>注入该方法:

public Startup(IConfiguration configuration)
{
// ...
public void Configure(IApplicationBuilder app, , IWebHostEnvironment env, ILogger<Startup> logger)
{
logger.LogError("Failed to do something"); 
}
}

你真的需要在ConfigureServices中记录吗?还是需要记录正在更新的选项?

对于任何遵循选项模式的东西(以及所有内置服务),你可以在lambda中配置选项,注入其他服务;

services.AddMvc();
services.AddOptions<MvcOptions>()
.Configure<ILogger<Startup>>((options, logger) => {
options.something = X;
logger.LogInformation($"... {X} ...");
});

注意services.AddMvc(options => {...});扩展方法在内部也做了类似的事情。

或者通过专用服务执行配置;

services.AddTransient<IConfigureOptions<MvcOptions>, ConfigureMvcOptions>();
public class ConfigureMvcOptions : IConfigureOptions<MvcOptions>{
private readonly ILogger<ConfigureMvcOptions> logger;
public ConfigureMvcOptions(ILogger<ConfigureMvcOptions> logger){
...
}

public void Configure(MvcOptions config)
{
options.something = X;
logger.LogInformation($"... {X} ...");
}
}

或者是一种服务;

services.AddSingleton<ConfigureEverything>();
services.AddSingleton<IConfigureOptions<MvcOptions>>(p => p.GetService<ConfigureEverything>());
services.AddSingleton<IConfigureOptions<SomethingElse>>(p => p.GetService<ConfigureEverything>());
// etc
public class ConfigureMvcOptions : 
IConfigureOptions<MvcOptions>,
IConfigureOptions<SomethingElse>,
// etc

显然,这是不灵活的,只是创建一个启动日志。在上述所有情况下,配置方法只在第一次使用时调用,一旦通用主机启动。

最新更新