Serilog.Sinks.ApplicationInsights与AddStandardResilienceHandler冲突致ComponentNotRegisteredException
问题背景
项目通过Serilog结合Serilog.Sinks.ApplicationInsights,配合services.AddApplicationInsightsTelemetry()实现日志同步到App Insights,原配置如下:
.UseSerilog((context, services, loggerConfiguration) => { loggerConfiguration .ReadFrom.Configuration(context.Configuration) .WriteTo.ApplicationInsights( services.GetRequiredService<TelemetryConfiguration>(), TelemetryConverter.Traces); //.WriteTo.Async(c => c.OpenTelemetry()); });
原本运行正常,添加.NET Aspire后出现报错:
Autofac.Core.Registration.ComponentNotRegisteredException: '请求的服务"Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration"未注册'
经排查,错误由ServiceDefaults项目中的以下代码触发:
builder.Services.ConfigureHttpClientDefaults(http => { http.AddStandardResilienceHandler(); }
注释掉AddStandardResilienceHandler()后,依赖注入可正常找到TelemetryConfiguration。需明确问题原因,以及如何同时保留AddStandardResilienceHandler()和原日志配置。
已找到临时解决方案,但该方案需手动创建TelemetryConfiguration,不够合理,希望保留原DI注入的方式:
.WriteTo.ApplicationInsights( MakeTelemetryConfiguration(builder), TelemetryConverter.Traces); private static TelemetryConfiguration MakeTelemetryConfiguration(WebApplicationBuilder builder) { var disableAppInsightsTelemetry = string.IsNullOrEmpty(builder.Configuration["APPINSIGHTS_INSTRUMENTATIONKEY"]); if (disableAppInsightsTelemetry) { return new TelemetryConfiguration { DisableTelemetry = true, }; } return new TelemetryConfiguration { InstrumentationKey = builder.Configuration["APPINSIGHTS_INSTRUMENTATIONKEY"], }; }
原因分析
.NET Aspire的AddStandardResilienceHandler()会引入Polly resilience组件,Autofac在处理HttpClient相关服务注册时,会改变DI容器的服务解析优先级和注册规则。AddApplicationInsightsTelemetry()默认注册的TelemetryConfiguration是带名称的默认实例(名称为TelemetryConfiguration.DefaultName),但AddStandardResilienceHandler()引入的Autofac扩展逻辑干扰了默认服务的解析,导致直接调用services.GetRequiredService<TelemetryConfiguration>()无法找到未命名的服务实例。
解决方法
方法1:显式获取命名的默认TelemetryConfiguration
直接指定默认实例的名称来获取服务,适配Application Insights的默认注册规则:
.WriteTo.ApplicationInsights( services.GetRequiredService<TelemetryConfiguration>(Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration.DefaultName), TelemetryConverter.Traces);
方法2:显式注册无命名的TelemetryConfiguration单例
在调用AddApplicationInsightsTelemetry()后,将默认命名实例注册为无命名的单例服务,确保DI容器能直接解析:
builder.Services.AddApplicationInsightsTelemetry(); // 显式将默认实例注册为无命名服务 builder.Services.AddSingleton(sp => sp.GetRequiredService<TelemetryConfiguration>(TelemetryConfiguration.DefaultName));
方法3:兼容式获取服务
在Serilog配置中增加兼容逻辑,优先获取命名实例,失败则创建默认实例,避免DI解析失败:
.UseSerilog((context, services, loggerConfiguration) => { var telemetryConfig = services.GetService<TelemetryConfiguration>(TelemetryConfiguration.DefaultName) ?? TelemetryConfiguration.CreateDefault(); loggerConfiguration .ReadFrom.Configuration(context.Configuration) .WriteTo.ApplicationInsights(telemetryConfig, TelemetryConverter.Traces); });
内容的提问来源于stack exchange,提问作者Lee Richardson

