Health Check Middleware

Add health check Middleware in the startup/ program

In this article, we will learn how to create an API that uses HealthCheck middleware.

What's health check middleware?

It's an extension built in .net core used to monitor web applications or a microservice. It comes with a set of services and middleware. To use the health check you need to register the service and then you can add your check.

How to do that, is simply you can add the below code to your ConfigureServices method in your Startup. cs file(for .net version 5 and less)

services.AddHealthChecks()

Then you need to configure an endpoint to map your check to a route, add the below code as an endpoint to Configure the method in Startup.cs :

endpoints.MapHealthChecks("/hc");

Note: you can specify any route you want this just an example.

If you run your application and go to your specified URL you would get the below result:

Implement the health check interface (IHealthcheck)

To get useful results we will implement a check called internet control message protocol ICMP, or simply a Ping check.

To add this check to our service we will need first to create a custom class that implements the IHealthCheck interface.

The interface IHealthCheck has one method CheckHealthAsync which runs the health check and returns the status of the component being checked:

Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext, CancellationToken)
  • How this check is getting executed by C# compiler?

    Since we want to run a ping test we will use the method SendPingAsync(Host) after instantiating a Ping object. Then we will return a HealthCheckResult depending on the status we are getting from our ping method.

public class PingHealthCheck : IHealthCheck { 
public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default(CancellationToken)) { 
try 
{ 
using var ping = new Ping(); 
var reply = await ping.SendPingAsync(Host);  
switch (reply.Status) { 
case IPStatus.Success: 
return (reply.RoundtripTime > HealthyRoundtripTime) ? HealthCheckResult.Degraded() : HealthCheckResult.Healthy(); 
default: 
return HealthCheckResult.Unhealthy();  
} 
} 
catch (Exception e) { 
return HealthCheckResult.Unhealthy();  
}  
} 
}

Note that a method used for a check is called AddCheck and it takes two parameters string as the name of the check and IHealthCheck object.

Customize health check options

In this step, we will add our check with options that would allow us to get more convenient results instead of the simple healthy, unhealthy text.

What we need to get is more details about our Ping request so we will start by modifying our class to return more data.

From where we are getting this text?! It appears that there is a property in HealthCheckOptions class called ResponseWriter. The default value is a delegate that will write a minimal text/plain response with the value of Status as a string.

Func<HttpContext,HealthReport,Task> ResponseWriter { get; set; }

So to change this we need to create our custom options class and override this property. So we will extend the class and set the property in our constructor to return a JSON response instead of the default text one.

public class CustomHealthCheckOptions : HealthCheckOptions { 
public CustomHealthCheckOptions() : base() { 

var jsonSerializerOptions = new JsonSerializerOptions() { WriteIndented = true }; 
ResponseWriter = async (c, r) => { 
c.Response.ContentType = MediaTypeNames.Application.Json; 
c.Response.StatusCode = StatusCodes.Status200OK; 
var result = JsonSerializer.Serialize(new { 
checks = r.Entries.Select(e => new { 
name = e.Key, 

responseTime = e.Value.Duration.TotalMilliseconds, 
status = e.Value.Status.ToString(), 
description = e.Value.Description }), 
totalStatus = r.Status, totalResponseTime = r.TotalDuration.TotalMilliseconds, }, jsonSerializerOptions); 
await c.Response.WriteAsync(result);  
}; 
} 
} 
}

To use these custom options we will pass them as a parameter to our endpoint:

endpoints.MapHealthChecks("/hc", new CustomHealthCheckOptions());

Reference:

ASP.NET Core 5 and Angular: Full-stack web development with .NET 5 and Angular 11, 4th Edition by Valerio De Sanctis