You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

同一类实现带AddHealthCheck的类型化HttpClient遇BaseAddress为空问题

类型化HttpClient在健康检查中BaseAddress为空的问题排查与解决

问题场景

我开发的应用需要对接一个HTTP设备,按照微软推荐的方式基于IHttpFactory构建了类型化HttpClient:

builder.Services.AddHttpClient<ISynchronicProvider, SynchronicProvider>(client =>
{
    client.BaseAddress = new Uri($"{builder.Configuration["Synchronic:protocol"]}://{builder.Configuration["Synchronic:host"]}:{builder.Configuration["Synchronic:port"]}");
    client.SetBasicAuthentication(builder.Configuration["Synchronic:user"], builder.Configuration["Synchronic:pass"]);
});  

该实现支持扩展Polly、日志功能,调用SendOpenP1Async方法完全正常。

之后我单独实现健康检查逻辑,通过IHttpClientFactory创建HttpClient调用设备状态接口,注册SynchronicHealthCheck后运行正常。

但当我让SynchronicProvider同时实现ISynchronicProvider和IHealthCheck接口,改用注入的HttpClient实现健康检查方法时:

public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
{
    var response = await httpClient.GetAsync($"?E={telecommande.Emetteur}&T={telecommande.Status}", cancellationToken);

    return response.IsSuccessStatusCode ?
                    HealthCheckResult.Healthy("Synchronic device is healthly") :          
                    HealthCheckResult.Unhealthy("Synchronic device is unhealthy");
}

发现健康检查方法中的HttpClient的BaseAddress为空,但其他方法里的BaseAddress是正常的。调整AddHttpClient和AddHealthChecks的注册顺序后,问题依然存在。

问题原因

这是因为.NET健康检查系统在实例化IHealthCheck实现类时,没有使用由AddHttpClient注册的类型化客户端实例,而是直接从DI容器中解析了一个全新的SynchronicProvider实例——这个实例并未关联到配置好的类型化HttpClient,所以注入的HttpClient是默认的、未配置BaseAddress的实例。

具体细节:

  • 通过AddHttpClient<ISynchronicProvider, SynchronicProvider>注册时,DI容器中会生成两个注册项:一个是ISynchronicProvider指向由HttpClientFactory包装的SynchronicProvider实例(带配置好的HttpClient);另一个是原始的SynchronicProvider类型注册(不带配置的HttpClient)。
  • 健康检查系统解析IHealthCheck时,会直接请求SynchronicProvider类型的实例,而非通过ISynchronicProvider接口,因此拿到的是未被HttpClientFactory处理过的实例,导致注入的HttpClient缺少BaseAddress配置。

解决方法

方法一:注册健康检查时指定通过接口解析实例

在注册健康检查时,明确要求DI容器通过ISynchronicProvider接口获取实例,这样就能拿到带有配置好的HttpClient的实例:

builder.Services.AddHealthChecks()
    .AddCheck<ISynchronicProvider>("synchronic_health_check");

方法二:手动关联类型化客户端到健康检查实例

如果必须直接使用SynchronicProvider类型注册健康检查,可以通过工厂方法从DI容器中获取正确的实例:

builder.Services.AddHealthChecks()
    .AddCheck("synchronic_health_check", sp => 
        sp.GetRequiredService<ISynchronicProvider>() as IHealthCheck);

方法三:确保类型化客户端实例被全局复用

移除SynchronicProvider的单独注册(如果存在),确保DI容器中只有AddHttpClient注册的实例,再通过接口注册健康检查:

// 仅保留AddHttpClient的注册,不要单独注册SynchronicProvider
builder.Services.AddHttpClient<ISynchronicProvider, SynchronicProvider>(client =>
{
    client.BaseAddress = new Uri($"{builder.Configuration["Synchronic:protocol"]}://{builder.Configuration["Synchronic:host"]}:{builder.Configuration["Synchronic:port"]}");
    client.SetBasicAuthentication(builder.Configuration["Synchronic:user"], builder.Configuration["Synchronic:pass"]);
});

// 通过接口注册健康检查
builder.Services.AddHealthChecks()
    .AddCheck<ISynchronicProvider>("synchronic_health_check");

内容的提问来源于stack exchange,提问作者User.Anonymous

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 11:32:33