ASP.NET Core中Startup与ConfigureServices间Logger被释放问题
问题原因
你在Startup构造函数中使用using var声明loggerFactory,该声明的作用域为当前构造函数代码块,构造函数执行完成后,loggerFactory会被立即自动释放。
你创建的StartupLogger实例依赖loggerFactory持有的所有日志提供器(包括EventLog日志提供器内部的EventLogInternal实例),loggerFactory释放时会连带销毁所有内部注册的日志提供器实例。当代码执行到ConfigureServices方法时,底层日志写入依赖的对象已经被释放,自然会抛出对象已释放的异常。
修复方案
方案1:持有LoggerFactory引用,延长其生命周期
将loggerFactory也定义为Startup类的实例字段,让它的生命周期和Startup实例保持一致,覆盖从构造函数执行到ConfigureServices调用的完整启动阶段,代码示例如下:
public class Startup { private readonly ILoggerFactory _startupLoggerFactory; public Startup(IConfiguration configuration) { Configuration = configuration; // 注意:这里不要加using关键字,避免提前释放 _startupLoggerFactory = LoggerFactory.Create(builder => { builder.SetMinimumLevel(LogLevel.Error); builder.AddEventLog(s => { s.LogName = "MyLogName"; s.SourceName = "MySource"; }); // 其他需要的持久化日志提供器 }); StartupLogger = _startupLoggerFactory.CreateLogger<Startup>(); } public IConfiguration Configuration { get; } public ILogger StartupLogger { get; } public void ConfigureServices(IServiceCollection services) { // 此处调用日志写入不会再触发对象已释放异常 StartupLogger.LogError("Failed to do something"); } // 可选:Startup实例生命周期结束时手动释放日志工厂 public void Dispose() { _startupLoggerFactory?.Dispose(); } }
方案2:使用主机内置的启动日志能力
ASP.NET Core 通用主机在构建阶段就已经初始化了基础日志能力,你不需要在Startup中手动创建LoggerFactory,可以直接在主机构建阶段获取日志实例传入Startup,完全不需要手动维护日志工厂的生命周期,日志配置也可以和应用运行阶段保持统一。
注意事项
- 不要对生命周期长于当前代码块的依赖对象使用
using声明,除非你明确控制对象的释放时机。 - 如果启动阶段日志需要写入到和应用运行阶段相同的目标,建议直接在主机配置日志环节统一配置提供器,避免重复维护日志配置逻辑。
内容的提问来源于stack exchange,提问作者T.S.
相关产品推荐
相关产品推荐

