From time to time it happens that the connection to the database fails or the services or containers crash. This can lead to a considerable investigation effort to find the reasons why these problems occur, which can be facilitated by the use of “HealthChecks”.
ASP.NET provides a convenient and effective approach to implementing this functionality.
To achieve this, the following nuggets need to be installed:
To include the following items in the Program.cs file:
builder.Services.AddHealthChecks();
...
...
//Now the HealthChecks should be mapped to the current endpoint
app.MapHealthChecks("/_health");
This would provide us with the foundation to check the health of our application. Currently, no checks are performed, so our application is considered to be in a healthy state.
Upon launching the app, initially, only the Swagger site is loaded and no other content is visible. Let’s simply update the address to:
To extend our HealthCheck with a custom check, we will create a new class called “MyFirstHealthCheck” with the following content:
public class MyFirstHealthCheck : IHealthCheck
{
public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
{
return Task.FromResult(HealthCheckResult.Healthy("This could be a service"));
}
}
This class serves the purpose of returning a “HealthCheckResult” with the status “Healthy”.
We have reached a point where we need to include this check in our Program.cs file. When we call this check, the situation looks a little different. Initially, the appearance remains unchanged. However, if we set a breakpoint in the source code, it will be triggered when we refresh the page.
Instead of using the term “healthy”, which is not very meaningful, it would be more helpful to convey a specific message. For example, we could use a more descriptive message to communicate the status or result of the test.
To accomplish this, we need to ensure that the NuGet package “AspNetCore.HealthChecks.UI.Client” is installed. After that, we can proceed to extend the following functionality:
In the Program.cs file, we need to incorporate a ResponseWriter into the mapper of the HealthCheck. This will enable us to customize the output or response generated by the HealthCheck module.
Let’s restart the program and see what comes out of it.
To enable easy retrieval from a list, we can assign a tag to this check. Implementing the tag in the service would facilitate the process.
Now let’s execute this request once more.
It can be a bit overwhelming at first.
To create a dashboard that lists all our checks using the NuGet package “AspNetCore.HealthChecks.UI.Client," we need to make three additions to the Program.cs file:
1. Add a new service:
This new dashboard requires persistent storage, so we need to add the NuGet package “AspNetCore.HealthChecks.UI.InMemory.Storage."
2. New Mapping
Below the previous AddHealthChecks() method call, we can add a new method call AddHealthChecksUI() that uses the in-memory store.
To map this new user interface, we can add a route to the Configure() method in the Startup.cs file. The route should point to the Health Checks UI endpoint.
3.) AppSettings.json
To configure the dashboard to forward requests to the appropriate address, you can modify the appsettings.json file. Within the file, you will need to update the relevant settings to specify the desired address for request forwarding.
We start the application and change the address:
By utilizing the dashboard we have created, we can now have a comprehensive overview of the checks we have implemented for our application. The dashboard not only displays the current status of the checks but also provides a history section that gives us insights into the events that have occurred from the application’s start until now. To access more detailed information, we can explore the details section within the dashboard.
What could a HealthCheck that monitors the connection to the database look like?
We create a new object that checks the connection to the database.
public class DatabaseConnectionCheck : IHealthCheck
{
public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
{
try
{
using var connection = new SqlConnection("Data Source=.;Initial Catalog=MyDatabase;Integrated Security=True;Connect Timeout=30;Encrypt=False;Trust Server Certificate=False;Application Intent=ReadWrite;Multi Subnet Failover=False");
await connection.OpenAsync(cancellationToken).ConfigureAwait(false);
using var command = connection.CreateCommand();
command.CommandText = "Select 1";
object result = await command.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false);
return HealthCheckResult.Healthy("The status of the connection is open");
}
catch (Exception ex)
{
return HealthCheckResult.Unhealthy("The status of the connection is close");
}
}
}
Here only the connection to the database is established and by the select 1 it is checked whether the query can be sent or not. Accordingly, a result is returned which is healthy or unhealthy.
Now we only have to announce the service:
Now we have a comprehensive overview of all the checks that have been configured in our application. This provides a clear and organized display of the various checks and their respective statuses, making it easier to monitor and track the health of our application.
these checks are queried every 5 seconds as we set, now if the connection to the database is closed or interrupted, this dashboard will react to it:
Top comments (0)