asp.net core健康检查需通过addhealthchecks()获取ihealthchecksbuilder注册检查项,自定义类须实现ihealthcheck接口;http端点用maphealthchecks暴露,默认json精简响应,可自定义responsewriter输出详情;数据库检查默认不真连,需指定healthquery或启用ef检测;并发执行各检查项并聚合状态,中间件顺序须在userouting后、useendpoints前。

HealthCheckService 和 IHealthChecksBuilder 怎么用
ASP.NET Core 的健康检查不是靠手动轮询或写个 GET /health 就完事的,它依赖内置的 HealthCheckService 后台服务和 IHealthChecksBuilder 注册机制。你得先在 Program.cs 里调用 AddHealthChecks(),它返回的就是 IHealthChecksBuilder 实例,所有检查项都通过它添加。
常见错误是直接 new 一个自定义类然后塞进 DI 容器,结果健康端点返回始终是 Healthy 或直接 500——因为没走健康检查管道,HealthCheckService 根本不知道它存在。
- 必须用
services.AddHealthChecks().AddCheck<MyDbHealthCheck>("db"),不能只注册MyDbHealthCheck类型 - 自定义检查类必须实现
IHealthCheck接口,且CheckHealthAsync方法不能抛未捕获异常(会转成Unhealthy,但堆栈不返回给客户端) - 如果检查逻辑含异步 IO(如数据库连接测试),必须用
await,别用.Result或.Wait(),否则可能死锁
如何添加 HTTP 端点并控制响应格式
注册完检查项后,还得暴露一个可访问的 endpoint,靠的是 MapHealthChecks 扩展方法。它默认返回 JSON,但字段精简(只有 status、results),不包含耗时、异常详情等调试信息。
开发阶段常需要看到每个检查项的执行时间或失败原因,这时得启用 ResponseWriter 自定义输出逻辑,而不是改用第三方中间件拦截响应体。
app.MapHealthChecks("/health", new HealthCheckOptions { ResponseWriter = WriteDetailedHealthResponse })-
WriteDetailedHealthResponse是个委托,接收HttpContext和HealthReport,可序列化report.Entries中每个HealthReportEntry的Exception、Duration属性 - 生产环境禁用详细输出,避免泄露内部信息;可用
Environment.IsDevelopment()控制开关
数据库连接健康检查为什么总是 Healthy 即使连不上
用 AddSqlServer、AddNpgsql 等扩展方法时,默认只检查连接字符串能否解析,不真连数据库。这是为了性能——健康检查端点不该成为 DB 连接风暴源头。
真正验证连通性,得传入 configureOptions 参数,开启 includeEntityFramework 或显式调用 Open() + Close()。
- SQL Server:
.AddSqlServer(connectionString, healthQuery: "SELECT 1", name: "sql")——healthQuery是关键,不设就只是解析连接字符串 - EF Core 场景下,若用了
AddDbContextHealthCheck<AppDbContext>,它默认会调用context.Database.CanConnectAsync(),但前提是上下文已正确注册且无作用域问题 - 注意连接超时:健康检查默认超时 30 秒,可通过
timeout参数缩短,比如timeout: TimeSpan.FromSeconds(5)
多个健康检查并发执行时状态怎么聚合
默认策略是「任意一项 Unhealthy → 整体 Unhealthy」,由 HealthReport.Status 的计算逻辑决定。这个聚合行为不可配置,但你可以用 RequireHealthy 或 RequireHealthyExcept 分组控制依赖关系。
比如缓存服务挂了不影响主流程,但数据库挂了必须告警,这时就得拆成两个 endpoint,而不是塞进同一个检查组。
- 用
AddCheck注册的每一项独立执行,彼此不阻塞;HealthCheckService并发运行它们(非顺序) - 想让某些检查仅在其他检查 Healthy 时才运行?不行——框架不支持条件触发,需在
CheckHealthAsync内部手动判断并返回HealthCheckResult.Degraded()或跳过逻辑 - 聚合结果中的
HealthReport.TotalDuration是所有检查最大耗时,不是总和;单个检查若超时,会被取消并标记为Unhealthy
最易忽略的一点:健康检查中间件在请求管道的位置。它必须放在 UseRouting 之后、UseEndpoints 之前,否则 MapHealthChecks 不生效。顺序错,/health 就 404。










