Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NetCore 2.2 - Health Check Support #1058

Closed
say25 opened this issue Mar 6, 2019 · 11 comments
Closed

NetCore 2.2 - Health Check Support #1058

say25 opened this issue Mar 6, 2019 · 11 comments

Comments

@say25
Copy link
Contributor

say25 commented Mar 6, 2019

Feature Request

Support for NetCore 2.2 Health Checks

Description

I have health checks set up using the new NetCore 2.2 health checks yet they do not show in Swagger UI. Can we add support for this to Swashbuckle.AspNetCore?

@domaindrivendev
Copy link
Owner

Swashbuckle is built on top of ApiExplorer, the API metadata component, that ships with ASP.NET Core.

If health-checks endpoints aren't surfaced by that, then they won't be surfaced by Swashbuckle. This is a fundamental aspect to the SB design and is unlikely to change anytime soon.

IMO, this sounds like a perfect candidate for a community add-on package (see https://github.com/domaindrivendev/Swashbuckle.AspNetCore#community-packages).

If there was a willing contributor, they could start a new project called Swashbuckle.AspNetCore.HealthChecks, that exposes an extension method on SwaggerGenOptions for enabling the functionality - e.g. EnableHealthCheckDescriptions. Then behind the scenes, this could be implemented as a Document Filter (see readme) that adds the relevant Operation descriptions to the Swagger/OAI document generated by Swashbuckle.

@tomkerkhove
Copy link
Contributor

tomkerkhove commented Jul 3, 2019

For those interested in this, you can expose a pass-through API endpoint based on HealthCheckService which is used behind the scenes via AddHealthChecks:

 [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>
    [HttpGet]
    [ProducesResponseType(typeof(HealthReport), (int)HttpStatusCode.OK)]
    [SwaggerOperation(OperationId = "Health_Get")]
    [SwaggerResponse((int)HttpStatusCode.OK, Description = "API is healthy")]
    [SwaggerResponse((int)HttpStatusCode.ServiceUnavailable, Description = "API is not healthy")]
    public async Task<IActionResult> Get()
    {
        var report = await _healthCheckService.CheckHealthAsync();
        return report.Status == HealthStatus.Healthy ? Ok(report) : StatusCode((int)HttpStatusCode.ServiceUnavailable, report);
    }
}

@markshoe
Copy link

I took a similar approach to @tomkerkhove, but since I wanted to retain the ability to customize the response using the HealthCheckOptions.ResponseWriter and use the ActionResult pattern, I created a HealthCheckActionResult

    public class HealthCheckActionResult : ActionResult
    {
        private readonly HealthCheckOptions _healthCheckOptions;
        private readonly HealthCheckService _healthCheckService;

        public HealthCheckActionResult(HealthCheckService healthCheckService, HealthCheckOptions healthCheckOptions)
        {
            _healthCheckOptions = healthCheckOptions;
            _healthCheckService = healthCheckService;
        }

        public HealthReport HealthReport { get; private set; }

        public override async Task ExecuteResultAsync(ActionContext context)
        {
            HealthReport = await _healthCheckService.CheckHealthAsync(_healthCheckOptions.Predicate, context.HttpContext.RequestAborted);
            context.HttpContext.Response.StatusCode = _healthCheckOptions.ResultStatusCodes[HealthReport.Status];
            await _healthCheckOptions.ResponseWriter(context.HttpContext, HealthReport);
        }
    }

And then in my controller,

        private readonly HealthCheckService _healthCheckService;
        private readonly HealthCheckOptions _healthCheckOptions;

        public DiagnosticsController(HealthCheckService healthCheckService, HealthCheckOptions healthCheckOptions = null)
        {
            _healthCheckService = healthCheckService ?? throw new ArgumentNullException(nameof(healthCheckService));
            _healthCheckOptions = healthCheckOptions ?? new HealthCheckOptions();
        }

        [HttpGet("healthcheck")]
        public HealthCheckActionResult GetHealthReport()
        {
            return new HealthCheckActionResult(_healthCheckService, _healthCheckOptions);
        }

@andreacassioli
Copy link

@tomkerkhove which version of Swashbuckle.AspNetCore are you running on? I am using your same approach, but I get a lot of errors resolving the response type.

` ``
[HttpGet]
[ProducesResponseType(typeof(HealthReport), 200)]
[Route("/health")]
public async Task DataHealth()
{
var report = await _sqlDataStatusService.GetDataHealth();
var healthReport = new HealthReport(report, DateTime.UtcNow);
return Ok(healthReport);
}


running locally, I see requests from the swagger like
``
Request starting HTTP/1.1 GET http://localhost:5002/swagger/doc/doc/doc/doc/doc/doc/doc/doc/doc/swagger.json 

and the UI reports Resolver errorCannot read property '$ref' of undefined.

Any clue?

@tomkerkhove
Copy link
Contributor

I'm using a variety of versions, which one are you using? Keep in mind that 5.x uses new serializer and might be due to that.

@andreacassioli
Copy link

@tomkerkhove I am running on 5.0.0, so I guess the serialiser might be an issue then.

@andreacassioli
Copy link

@tomkerkhove upgrading to 5.4.0 did the trick.

However the example makes no sense, even though the model is correct. Not a big deal anyway.

Thanks.

@tomkerkhove
Copy link
Contributor

Happy to help!

@domaindrivendev
Copy link
Owner

@say25 (and others) can this be closed or is there still an outstanding issue?

@say25
Copy link
Contributor Author

say25 commented Apr 29, 2020

I mean I think to some extent we can close but I do think it would be cool if these HealthChecks were exposed in ApiExplorer but I think dotnet/aspnetcore#18153 covers it.

@say25 say25 closed this as completed Apr 29, 2020
@richtea
Copy link

richtea commented Dec 11, 2022

IMO, this sounds like a perfect candidate for a community add-on package (see https://github.com/domaindrivendev/Swashbuckle.AspNetCore#community-packages).

If there was a willing contributor, they could start a new project called Swashbuckle.AspNetCore.HealthChecks, that exposes an extension method on SwaggerGenOptions for enabling the functionality - e.g. EnableHealthCheckDescriptions. Then behind the scenes, this could be implemented as a Document Filter (see readme) that adds the relevant Operation descriptions to the Swagger/OAI document generated by Swashbuckle.

I have created a package Swashbuckle.AspNetCore.HealthChecks that provides this functionality, although with a different interface from the one proposed. Currently in alpha although it's been running successfully for quite a while in a couple of my projects.

The repo contains samples and documentation. Feedback welcome, please raise an issue in that repo if you would like to see a particular feature or have any other comments or questions.

@domaindrivendev I took the liberty of calling it Swashbuckle.AspNetCore.HealthChecks as suggested, for discoverability - I hope this isn't taken the wrong way. I'd be happy to rename it if you prefer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants