Application Health Check Using ASP.NET Core

Agenda

In this article, we will learn about application health check middleware that .net core provides and understand various checks we can perform using this middleware.

Prerequisite

  • Knowledge of .net core middleware

Application health has become the core of any business. An application that is not stable (unhealthy) leads to lots of revenue loss, customer trust, and negative impacts on business. To avoid such cases, we should regularly monitor the status of our applications.

Application health checks are when you define “healthy” parameters for the monitoring metrics across your application and run regular checks to ensure the system is performing the way it’s expected to.

Using these health checks, we can be notified of outages before customers and reduce the impact of outages by fixing them or informing the customer about the ongoing outage with time which leads to gaining trust.

Monitoring depends on the complexity and criticality of the application. A simple application may require monitoring its dependencies once a day, whereas a critical application may be required to be monitored as frequently as possible. We can also provide a status page to see the results and add functionality to notify developers about problems.

Let’s see how we can do these health checks using asp.net core,

Every dotnet core application implicitly refers a package Microsoft.AspNetCore.Diagnostics.HealthChecks package which makes it easy to add a basic health check to our application.

Basic health check

So, to enable the health check endpoint we need to do two code changes below (highlighted in yellow) to our startup.cs file

Enable to health check endpoint

Apart from these two lines, we are not doing anything but when we try to call the health route endpoint it returns the status of my application.

Healthy

Three types of health status are returned to the monitoring service which uses the health check.

  • Degraded: Indicates that the component was in a degraded state.
  • Healthy: Indicates that the component was healthy.
  • Unhealthy: Indicates that the component was unhealthy, or an unhandled exception was thrown while executing the health check.

In the real world, this basic health check won't be enough to know the status of the app, we need to monitor the health of dependencies of the application like a database or other external API or storage account that is used in our application.

There are many NuGet packages available for commonly used services, I am listing a few packages below which are popularly used

Few package

We have to add the NuGet package and code in startup.cs file to do a basic health check for these services.

For SQL server health check

Install AspNetCore.HealthChecks.SqlServer package and add the below-highlighted code.

SQL server health check

This will check our SQL DB health before returning the result to the health route endpoint which we added earlier.

For Azure storage health check

Install AspNetCore.HealthChecks.AzureStorage and add the below-highlighted code.

Azure storage health check

For URI health check

Install AspNetCore.HealthChecks.Uris and add the below-highlighted code.

Uri health check

There are many such packages that we can install and so changes to our startup file will do a health check for us.

Health check predicate options

We can also add tags to these health checks and add route filtering to execute health checks as shown below.

In the below example, I have added tags to health check profiles, so I can filter and get health status only for specific sets as per my requirement.

Health check predicate options

Changed endpoints as below.

Changed endpoints

In this way, we can configure a health check for our application and link to any external UI monitoring (for example https://uptimerobot.com/) or add AspNetCore.HealthChecks.UI NuGet package to your web project creates UI for monitoring.

Health checks are usually used with an external monitoring service or container orchestrator to check the status of an app. Before adding health checks to an app, decide on which monitoring system to use. The monitoring system dictates what types of health checks to create and how to configure their endpoints.

Code snippet for startup.cs

using Microsoft.AspNetCore.Builder;  
using Microsoft.AspNetCore.Diagnostics.HealthChecks;  
using Microsoft.AspNetCore.Hosting;  
using Microsoft.Extensions.Configuration;  
using Microsoft.Extensions.DependencyInjection;  
using Microsoft.Extensions.Hosting;  
using System;  
namespace Healthchecks {  
    public class Startup {  
        public Startup(IConfiguration configuration) {  
            Configuration = configuration;  
        }  
        public IConfiguration Configuration {  
            get;  
        }  
        // This method gets called by the runtime. Use this method to add services to the container.  
        public void ConfigureServices(IServiceCollection services) {  
            services.AddControllers();  
            services.AddHealthChecks().AddSqlServer(Configuration["ConnectionStrings:dbConnectionString"], tags: new [] {  
                "db",  
                "all"  
            }).AddAzureBlobStorage(Configuration["ConnectionStrings:blobConnectionString"], tags: new [] {  
                "AzureStorage",  
                "all"  
            }).AddAzureQueueStorage(Configuration["ConnectionStrings:QueueConnectionString"], tags: new [] {  
                "AzureStorage",  
                "all"  
            }).AddUrlGroup(new Uri("https://testdemo.azurewebsites.net/health"), tags: new [] {  
                "testdemoUrl",  
                "all"  
            });  
            services.AddSwaggerGen();  
        }  
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.  
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {  
            if (env.IsDevelopment()) {  
                app.UseDeveloperExceptionPage();  
            }  
            app.UseHttpsRedirection();  
            app.UseSwagger();  
            app.UseSwaggerUI(s => {  
                s.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");  
            });  
            app.UseRouting();  
            app.UseAuthorization();  
            app.UseEndpoints(endpoints => {  
                endpoints.MapControllers();  
                endpoints.MapHealthChecks("/health", new HealthCheckOptions() {  
                    Predicate = (check) => check.Tags.Contains("all")  
                });  
                endpoints.MapHealthChecks("/health/AzureStorage", new HealthCheckOptions() {  
                    Predicate = (check) => check.Tags.Contains("AzureStorage")  
                });  
            });  
        }  
    }  
}  

I hope you liked this article. In case you found the article useful then kindly like and share it.