5
votes

Intégration du point de terminaison HealthCheck dans l'interface utilisateur Swagger (API ouverte) sur dotnet core

J'utilise les contrôles de santé Dotnet Core comme décrit ici . En bref, cela ressemble à ceci:

Tout d'abord, vous configurez des services comme ceci:

app.UseHealthChecks("/my/healthCheck/endpoint");

Ensuite, vous enregistrez un point de terminaison comme celui-ci:

services.AddHealthChecks()
    .AddSqlServer("connectionString", name: "SQlServerHealthCheck")
    ... // Add multiple other checks

Nous utilisons également Swagger (alias Open API) et nous voyons tous les points de terminaison via l'interface utilisateur Swagger, mais pas le point de terminaison de vérification de l'état.

Y a-t-il un moyen d'ajouter ceci à une méthode de contrôleur pour que Swagger récupère automatiquement le point de terminaison, ou peut-être l'intégrer avec swagger d'une autre manière?

La meilleure solution que j'ai trouvée jusqu'à présent est d'ajouter un point de terminaison personnalisé codé en dur ( comme décrit ici ), mais ce n'est pas agréable à maintenir.


0 commentaires

5 Réponses :


5
votes

Toujours à la recherche d'une meilleure solution, mais la solution d'un pauvre homme à ce problème ressemble à ceci:

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);
}


2 commentaires

Existe-t-il une version de ceci qui fonctionne avec Swagger 5.0.0 (utilisant les objets OpenApi)?


@penny, je vois que vous avez travaillé là-dessus, merci pour le partage!



3
votes

Il n'y a pas de support intégré, soit vous développez manuellement une solution du pauvre comme dans la réponse acceptée , soit vous développer une extension comme mentionné dans ce problème GitHub: NetCore 2.2 - Support Health Check

Swashbuckle est construit sur ApiExplorer , le composant de métadonnées API, fourni avec ASP.NET Core.

Si les points de terminaison des vérifications de l'état ne sont pas mis en évidence par cela, alors ils ne le seront pas par Swashbuckle. Il s'agit d'un aspect fondamental de la conception SB et il est peu probable que cela change de sitôt.

IMO, cela semble être un candidat parfait pour un package complémentaire de communauté (voir https://github.com/domaindrivendev/Swashbuckle.AspNetCore#community-packages ).

S'il y avait un contributeur volontaire, il pourrait démarrer un nouveau projet appelé Swashbuckle.AspNetCore.HealthChecks , qui expose une méthode d'extension sur SwaggerGenOptions pour activer la fonctionnalité - par exemple EnableHealthCheckDescriptions . Ensuite, dans les coulisses, cela pourrait être implémenté comme un filtre de document (voir readme) qui ajoute les descriptions d'opération pertinentes au document Swagger / OAI généré par Swashbuckle.


0 commentaires

0
votes

Ma solution de contournement consiste à ajouter le contrôleur factice suivant.

using HealthChecks.UI.Client;
using Microsoft.AspNetCore.Mvc;
using System;

[Route("[controller]")]
[ApiController]
[Produces("application/json")]
public class HealthController: ControllerBase
{
    [HttpGet("")]
    public UIHealthReport Health()
    {
        throw new NotImplementedException("");
    }
}


0 commentaires

6
votes

J'ai utilisé cette approche et cela a bien fonctionné pour moi: https://www.codit.eu/blog/documenting-asp-net-core-health-checks-with-openapi

Ajouter un nouveau contrôleur, par exemple HealthController et injectez HealthCheckService dans le constructeur. Le HealthCheckService est ajouté en tant que dépendance lorsque vous appelez AddHealthChecks dans Startup.cs:

Le HealthController devrait apparaître dans Swagger lorsque vous reconstruisez:

[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);
    }
}

Une chose J'ai cependant remarqué que le point de terminaison est toujours "/ health" (ou ce que vous avez défini dans Startup.cs) et non "/ api / vxx / health" mais il apparaîtra toujours correctement dans Swagger.

p >


1 commentaires

C'est la meilleure réponse de l'OMI. Je ne sais pas pourquoi Microsoft ne documente pas cette utilisation dans la documentation officielle, car il existe de nombreux cas où l'approche «officielle» ne résout pas le problème.



4
votes

Depuis que Swagger a été mis à jour, il y a un changement radical entre .NET 2.x et 3.1 / Swagger 4.0.0 et 5.0.0

Voici une version de la solution du pauvre (voir la réponse eddyP23) qui fonctionne avec 5.0.0.

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);
    }
}


0 commentaires