在IHostBuilder上使用Serilog时遇ILoggerFactory依赖注入错误及过时告警
解决依赖注入无法解析
ILoggerFactory的问题 致命错误信息
{"@t":"2023-07-13T06:47:04.5190466Z","@mt":"Host terminated unexpectedly.","@l":"Fatal","@x":"System.InvalidOperationException: Unable to resolve service for type 'Microsoft.Extensions.Logging.ILoggerFactory' while attempting to activate 'VehicleRepairService.Startup'.\r\n at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider)\r\n at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, Object[] parameters)\r\n at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.UseStartup(Type startupType, HostBuilderContext context, IServiceCollection services, Object instance)\r\n at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.<>c__DisplayClass13_0.<UseStartup>b__0(HostBuilderContext context, IServiceCollection services)\r\n at Microsoft.Extensions.Hosting.HostBuilder.CreateServiceProvider()\r\n at Microsoft.Extensions.Hosting.HostBuilder.Build()\r\n at VehicleRepairService.Program.Main(String[] args) in C:\\SoleraNA\\Backend\\Inspection\\vehiclerepairservice\\src\\vehiclerepairservice\\Program.cs:line 37"}
原始Program.cs代码
public static IWebHostBuilder CreateHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseSerilog() .UseKestrel(k => k.AddServerHeader = false) .UseContentRoot(Directory.GetCurrentDirectory()) .UseDefaultServiceProvider(options => options.ValidateScopes = false) .UseCloudFoundryHosting() // Add VCAP_* configuration data .AddCloudFoundry() .ConfigureLogging((builderContext, loggingBuilder) => { loggingBuilder.ClearProviders(); // avoid duplicated log entries loggingBuilder.AddSerilogDynamicConsole(); }) .UseStartup<Startup>();
过时警告
SerilogWebHostBuilderExtensions.UseSerilog(IWebHostBuilder, ILogger, bool, LoggerProviderCollection)' is obsolete: 'Prefer UseSerilog() on IHostBuilder'
修改后的Program.cs代码
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .UseSerilog() .UseContentRoot(Directory.GetCurrentDirectory()) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseKestrel(k => k.AddServerHeader = false) .UseCloudFoundryHosting() .AddCloudFoundry() .ConfigureLogging((builderContext, loggingBuilder) => { loggingBuilder.ClearProviders(); loggingBuilder.AddSerilogDynamicConsole(); }) .UseStartup<Startup>(); });
问题原因与解决方案
原因
改用Host.CreateDefaultBuilder后,Startup类的激活时机发生变化:在Host构建服务提供器的流程中,ILoggerFactory尚未完成注册,而Startup构造函数直接依赖该服务,导致DI容器无法解析。
解决方法
方案1:调整日志配置位置
将ConfigureLogging移到Host级别配置,确保日志服务在Startup激活前完成初始化:
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureLogging((context, loggingBuilder) => { loggingBuilder.ClearProviders(); loggingBuilder.AddSerilogDynamicConsole(); }) .UseSerilog() .UseContentRoot(Directory.GetCurrentDirectory()) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseKestrel(k => k.AddServerHeader = false) .UseCloudFoundryHosting() .AddCloudFoundry() .UseStartup<Startup>(); });
方案2:修改Startup类的依赖
避免在Startup构造函数中注入ILoggerFactory,改用以下方式:
- 注入
ILogger<Startup>替代(仅需日志记录场景) - 在
ConfigureServices或Configure方法中获取ILoggerFactory
示例修改后的Startup构造函数:
public class Startup { private readonly IConfiguration _config; private readonly ILogger<Startup> _logger; public Startup(IConfiguration config, ILogger<Startup> logger) { _config = config; _logger = logger; } // 其他方法... }
方案3:保留WebHostBuilder适配Serilog(临时过渡)
若暂时不想切换到HostBuilder,可更新Serilog使用方式消除过时警告:
public static IWebHostBuilder CreateHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseSerilog((context, loggerConfig) => { loggerConfig.ReadFrom.Configuration(context.Configuration); }) // 其他原有配置... .UseStartup<Startup>();
内容的提问来源于stack exchange,提问作者spindlyCoder832
相关产品推荐
相关产品推荐

