将 HealthCheck 端点集成到 dotnet 核心上的 swagger(开放 API)UI 中

edd*_*P23 9 swagger swagger-ui openapi asp.net-core-2.2

我正在使用此处描述的 Dotnet Core 运行状况检查。简而言之,它看起来像这样:

首先,您可以像这样配置服务:

services.AddHealthChecks()
    .AddSqlServer("connectionString", name: "SQlServerHealthCheck")
    ... // Add multiple other checks
Run Code Online (Sandbox Code Playgroud)

然后,您注册一个端点,如下所示:

app.UseHealthChecks("/my/healthCheck/endpoint");
Run Code Online (Sandbox Code Playgroud)

我们也在使用 Swagger(又名 Open API),我们通过 Swagger UI 查看所有端点,但看不到健康检查端点。

有没有办法将它添加到控制器方法中,以便 Swagger 自动获取端点,或者以另一种方式将它与 swagger 集成?

到目前为止,我发现的最佳解决方案是添加自定义硬编码端点(如此处所述),但维护起来并不好。

Cia*_*uen 8

我使用了这种方法,它对我来说效果很好:https : //www.codit.eu/blog/documenting-asp-net-core-health-checks-with-openapi

添加一个新控制器,例如 HealthController 并将 HealthCheckService 注入构造函数。当您在 Startup.cs 中调用 AddHealthChecks 时,将 HealthCheckService 添加为依赖项:

重建时 HealthController 应该出现在 Swagger 中:

[Route("api/v1/health")]
public class HealthController : Controller
{
    private readonly HealthCheckService _healthCheckService;
    public HealthController(HealthCheckService healthCheckService)
    {
        _healthCheckService = healthCheckService;
    }
     
    /// <summary>
    /// Get Health
    /// </summary>
    /// <remarks>Provides an indication about the health of the API</remarks>
    /// <response code="200">API is healthy</response>
    /// <response code="503">API is unhealthy or in degraded state</response>
    [HttpGet]
    [ProducesResponseType(typeof(HealthReport), (int)HttpStatusCode.OK)]
    [SwaggerOperation(OperationId = "Health_Get")]
    public async Task<IActionResult> Get()
    {
        var report = await _healthCheckService.CheckHealthAsync();

        return report.Status == HealthStatus.Healthy ? Ok(report) : StatusCode((int)HttpStatusCode.ServiceUnavailable, report);
    }
}
Run Code Online (Sandbox Code Playgroud)

我注意到的一件事是端点仍然是“/health”(或您在 Startup.cs 中设置的任何内容)而不是“/api/vxx/health”,但它仍然会在 Swagger 中正确显示。

  • 在我看来,这是最好的答案。我不确定为什么微软不在官方文档中记录这种用法,因为在很多情况下“官方”方法并不能解决这个问题。 (2认同)

pen*_*nny 6

由于 Swagger 已更新,.NET 2.x 和 3.1/Swagger 4.0.0 和 5.0.0 之间发生了重大变化

以下是适用于 5.0.0 的穷人解决方案版本(请参阅 eddyP23 答案)。

public class HealthChecksFilter : IDocumentFilter
{
    public const string HealthCheckEndpoint = @"/healthcheck";

    public void Apply(OpenApiDocument openApiDocument, DocumentFilterContext context)
    {
        var pathItem = new OpenApiPathItem();

        var operation = new OpenApiOperation();
        operation.Tags.Add(new OpenApiTag { Name = "ApiHealth" });

        var properties = new Dictionary<string, OpenApiSchema>();
        properties.Add("status", new OpenApiSchema() { Type = "string" });
        properties.Add("errors", new OpenApiSchema() { Type = "array" });

        var response = new OpenApiResponse();
        response.Content.Add("application/json", new OpenApiMediaType
        {
            Schema = new OpenApiSchema
            {
                Type = "object",
                AdditionalPropertiesAllowed = true,
                Properties = properties,
            }
        });

        operation.Responses.Add("200", response);
        pathItem.AddOperation(OperationType.Get, operation);
        openApiDocument?.Paths.Add(HealthCheckEndpoint, pathItem);
    }
}
Run Code Online (Sandbox Code Playgroud)


edd*_*P23 5

仍在寻找更好的解决方案,但穷人的解决方案是这样的:

public const string HealthCheckEndpoint = "/my/healthCheck/endpoint";

public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
{
    var pathItem = new PathItem();
    pathItem.Get = new Operation()
    {
        Tags = new[] { "ApiHealth" },
        Produces = new[] { "application/json" }
    };

    var properties = new Dictionary<string, Schema>();
    properties.Add("status", new Schema(){ Type = "string" });
    properties.Add("errors", new Schema(){ Type = "array" });
    
    var exampleObject = new { status = "Healthy", errors = new List<string>()};

    pathItem.Get.Responses = new Dictionary<string, Response>();
    pathItem.Get.Responses.Add("200", new Response() {
        Description = "OK",
        Schema = new Schema() {
            Properties = properties,
            Example = exampleObject }});

    swaggerDoc.Paths.Add(HealthCheckEndpoint, pathItem);
}
Run Code Online (Sandbox Code Playgroud)