C# 健康检查实现方法 C# ASP.NET Core如何添加健康检查

2次阅读

ASP.net Core健康检查需通过AddHealthChecks()获取IHealthChecksBuilder注册检查项,自定义类须实现IHealthCheck接口http端点用MapHealthChecks暴露,默认json精简响应,可自定义ResponseWriter输出详情;数据库检查默认不真连,需指定healthQuery或启用EF检测;并发执行各检查项并聚合状态,中间件顺序须在UseRouting后、UseEndpoints前。

C# 健康检查实现方法 C# ASP.NET Core如何添加健康检查

HealthCheckService 和 IHealthChecksBuilder 怎么用

ASP.NET Core 的健康检查不是靠手动轮询或写个 GET /health 就完事的,它依赖内置的 HealthCheckService 后台服务和 IHealthChecksBuilder 注册机制。你得先在 Program.cs 里调用 AddHealthChecks(),它返回的就是 IHealthChecksBuilder 实例,所有检查项都通过它添加。

常见错误是直接 new 一个自定义类然后塞进 DI 容器,结果健康端点返回始终是 Healthy 或直接 500——因为没走健康检查管道,HealthCheckService 根本不知道它存在。

  • 必须用 services.AddHealthChecks().AddCheck("db"),不能只注册 MyDbHealthCheck 类型
  • 自定义检查类必须实现 IHealthCheck 接口,且 CheckHealthAsync 方法不能抛未捕获异常(会转成 Unhealthy,但不返回给客户端)
  • 如果检查逻辑含异步 IO(如数据库连接测试),必须用 await,别用 .Result.Wait(),否则可能死锁

如何添加 HTTP 端点并控制响应格式

注册完检查项后,还得暴露一个可访问的 endpoint,靠的是 MapHealthChecks 扩展方法。它默认返回 JSON,但字段精简(只有 statusresults),不包含耗时、异常详情等调试信息。

开发阶段常需要看到每个检查项的执行时间或失败原因,这时得启用 ResponseWriter 自定义输出逻辑,而不是改用第三方中间件拦截响应体。

  • app.MapHealthChecks("/health", new HealthCheckOptions { ResponseWriter = WriteDetailedHealthResponse })
  • WriteDetailedHealthResponse 是个委托,接收 HttpContextHealthReport,可序列化 report.Entries 中每个 HealthReportEntryExceptionDuration 属性
  • 生产环境禁用详细输出,避免泄露内部信息;可用 Environment.IsDevelopment() 控制开关

数据库连接健康检查为什么总是 Healthy 即使连不上

AddsqlServerAddNpgsql 等扩展方法时,默认只检查连接字符串能否解析,不真连数据库。这是为了性能——健康检查端点不该成为 DB 连接风暴源头。

真正验证连通性,得传入 configureOptions 参数,开启 includeEntityFramework 或显式调用 Open() + Close()

  • SQL Server:.AddSqlServer(connectionString, healthQuery: "select 1", name: "sql") —— healthQuery 是关键,不设就只是解析连接字符串
  • EF Core 场景下,若用了 AddDbContextHealthCheck,它默认会调用 context.database.CanConnectAsync(),但前提是上下文已正确注册且无作用域问题
  • 注意连接超时:健康检查默认超时 30 秒,可通过 timeout 参数缩短,比如 timeout: TimeSpan.FromSeconds(5)

多个健康检查并发执行时状态怎么聚合

默认策略是「任意一项 Unhealthy → 整体 Unhealthy」,由 HealthReport.Status 的计算逻辑决定。这个聚合行为不可配置,但你可以用 RequireHealthyRequireHealthyExcept 分组控制依赖关系。

比如缓存服务挂了不影响主流程,但数据库挂了必须告警,这时就得拆成两个 endpoint,而不是塞进同一个检查组。

  • AddCheck 注册的每一项独立执行,彼此不阻塞;HealthCheckService 并发运行它们(非顺序)
  • 想让某些检查仅在其他检查 Healthy 时才运行?不行——框架不支持条件触发,需在 CheckHealthAsync 内部手动判断并返回 HealthCheckResult.Degraded() 或跳过逻辑
  • 聚合结果中的 HealthReport.TotalDuration 是所有检查最大耗时,不是总和;单个检查若超时,会被取消并标记为 Unhealthy

最易忽略的一点:健康检查中间件在请求管道的位置。它必须放在 UseRouting 之后、UseEndpoints 之前,否则 MapHealthChecks 不生效。顺序错,/health 就 404。

text=ZqhQzanResources