/application-health-checks

Sample solution for application health checks of ASP.NET Core 6 applications

Primary LanguageJavaScript

Application Health Checks of ASP.NET Core applications

Overview

The examples of application health checks are presented using sample ASP.NET Core applications, targeting .NET framework 6.0:

The solution contains 4 applications:

  • A frontend MVC .NET Core 6.0 application called Investment Manager coded originally by Pluralsight Author David Berry (https://app.pluralsight.com/profile/author/david-berry). This frontent application consists of 3 projects: InvestmentManager, InvestmentManager.Core and InvestmentManager.DataAccess.EF.
  • A backend API, called by the frontend applicaton to retrieve stock index data: 1 project named StockIndexWebService
  • HealthCheckAlerter is a .NET Core web application containing the RabbitMQ.Client NuGet package to process health check messages, display their status and send alert messages
  • IdentityServer used to provide OAuth2 JWT access token for authorizing health check endpoint

Solution in Visual Studio

- The frontend application can display investment accounts with asset allocation and account history charts, along with stock index data in the top row received from the API:

Investment account list

Investment account charts

 

Application health check examples

Liveness health checks

➡️ Liveness health check using the MapHealthChecks extension method (framework: Microsoft.AspNetCore.App, assembly: Microsoft.Extensions.Diagnostics.HealthChecks) Endpoint: /health

Liveness health check - code

Liveness health check - response

Code: https://github.com/sztrelcsikzoltan/application-health-checks/commit/8cc5d1d55e2e55a70b1f8bd13588b0f2c0e93297

 
 
➡️ Liveness health check for specific host name(s) and port number(s), using RequireHost extension method (framework: Microsoft.AspNetCore.App, assembly: Microsoft.AspNetCore.Routing) Endpoint: /health-on-host

Liveness health check for specific host and port - code

Liveness health check for specific host and port - response

Code: https://github.com/sztrelcsikzoltan/application-health-checks/commit/05571ebc06538efe697d9982a9f9c25a0432487a

 
 

Readiness health checks

➡️ Dependency health check of SQL server using the AddCheck extension method (framework: Microsoft.AspNetCore.App, assembly: Microsoft.Extensions.Diagnostics.HealthChecks) Health check name: "SQLServer in startup"

SQL server health check in startup

Code: https://github.com/sztrelcsikzoltan/application-health-checks/commit/fcd93e3098a7dd38378a257775f0fee4726a0608

 
 
➡️ Add SQL server health check using the AddSqlServer extension method (NuGet package: AspNetCore.HealthChecks.SqlServer, assembly: HealthChecks.SqlServer) Health check name: "SqlServer"

Add SqlServer health check with SqlServer package

Code: https://github.com/sztrelcsikzoltan/application-health-checks/commit/af69c0e76263e58cbbd6be96309b1261aa3fe3c7

 
 
➡️ Add endpoint health check, using the AddUrlGroup extension method (NuGet package AspNetCore.HealthChecks.Uris, assembly: HealthChecks.Uris) Health check name: "Stock Index API Health Check"

Add endpoint health check with Uris package

Code: https://github.com/sztrelcsikzoltan/application-health-checks/commit/29ec863022a78844e51a35f66ee99981d713370f

 
 
➡️ Health check with customized status codes, using the property ResultStatusCodes of type IDictionary <HealthStatus, int> (framework Microsoft.AspNetCore.App, assembly: Microsoft. AspNetCore.Diagnostics.HealthChecks)

  • for Degraded healtch status it changes the status code to 500, instead of default 200 Endpoint: /health-customized-status-code

Health check with customized status code - code

Health check with customized status code - response

Code: https://github.com/sztrelcsikzoltan/application-health-checks/commit/bed27ce63d17b09104fd77eb5b349521780c723a

 
 
➡️ Create separate endpoints for differently tagged health checks

  • /health/ready endpoint for health checks with "ready" tag
  • /health/live endpoint for health checks without "ready" tag

Create health check endpoints with and without ready tag

➡️ Create separate endpoints for differently tagged health checks:

  • /health/live endpoint:

10a customize content of /health-live endpoint - code

Customize content of /health/live endpoint - response

Code: https://github.com/sztrelcsikzoltan/application-health-checks/commit/290fa2da9d5fe45249866771fad939eb25f6c31e

 
 
➡️ Customize the content and format of health check responses:

  • /health/ready endpoint:

Customize content of /health/ready endpoint - code

Customize content of /health/ready endpoint - response

Code: https://github.com/sztrelcsikzoltan/application-health-checks/commit/18a884e1f09f4dc5d2565724bd1d61e878d1a59d

 
 
➡️ Add file path write health check using a class instance

  • health check name: "File Path Health Check class"

Add file path write check with class instance - code

Add file path write check with class instance - response

Code: https://github.com/sztrelcsikzoltan/application-health-checks/commit/5bce80b32e1cd398e7cf599e2296e5a619cd7b62

 
 
➡️ Add file path write health check using the extension method AddFilePathWrite

  • health check name: "File Path Health Check extension"

Add file path write check with extension method - code

Add file path write check with extension method - response

Code: https://github.com/sztrelcsikzoltan/application-health-checks/commit/332abf318219f73d5f27a455f63be109e8599baf

 
 
➡️ Add authorization policy to the health/ready endpoint, using the RequireAuthorization extension method (framework: Microsoft.AspNetCore.App, assembly: Microsoft.AspNetCore.Authorization.Policy). It uses OAuth2 authorization type with JSON Web Token authentication provided by IdentityServer.

  • add authorization policy to health check endpoint:

Add authorization policy to health check endpoint

  • configure JWT token request in Postman:

Configure token request in Postman

- JWT token issued by IdentityServer:

JWT token issued by IdentityServer

  • JWT token received in Postman:

JWT token received in Postman

  • Request to health check endpoint successful with the JWT token:

Request with token successful in Postman

Code: https://github.com/sztrelcsikzoltan/application-health-checks/commit/f70e7215c933d893f6563854c2da8557e5691c08

 
 
➡️ Add endpoint health checks as Controller action methods

  • the /health/controller endpoint returns customized status values of the enum type HealhStatus (framework Microsoft.AspNetCore.App, assembly: Microsoft. AspNetCore.Diagnostics.HealthChecks.Abstractions), which represents the reported status of a health check result:

Customized HealthStatus values

  • the /health/controller endpoint returns the customized property values of the HealthReport class (framework Microsoft.AspNetCore.App, assembly: Microsoft. AspNetCore.Diagnostics.HealthChecks.Abstractions), such as aggregate Status of health checks, Totalduration, as well as values of the Entries property such as Name, Status, Duration, Description and Exception of any individual health check:

Customized property values of the HealthReport class

  • the final result is formatted by TextWriter using the enum type Formating option Indented (package: NewtonSoft.Json, assembly: Newtonsoft.Json):

Property values of the HealthReport class

  • as a result each child object appears in a new line indented:

Final results of /health/controller endpoint

  • if the StockIndexWebService API is not available, the endpoint returns Degraded Status for this health check, along with Exception information:

Final results with Degraded status

  • if the physical path for health check FilePathWrite is not available, the endpoint returns Faiure Status for this health check, along with Exception information and the information defined in the Data dictionary:

Final results with Failure status

  • the /healthcheck endpoint redirects to the ./health/controller endpoint:

The /healthcheck endpoint redirects to ./health/controller endpoint

  • the /health/ping endpoint returns 200 (OK) status code to indicate that the dependency app is reachable:

The /health/ping endpoint returns status code 200

  • the /health/assembly endpoint returns assembly-related information, such as Application name, BuildDate, ProductVersion, AssembyVersion:

The /health/assembly endpoint - code

The /health/assembly endpoint - response

  • the controller endpoints are by default mapped in the http pipeline, using the MapControllerRoute extension method; (if needed, you can use the endpoints.MapControllers extension method):

Controller endpoints are mapped in Program.cs

Code: https://github.com/sztrelcsikzoltan/application-health-checks/commit/2020836690ba46138d9ca47aa686a7fd97f04b2c

 
 
➡️ Add endpoint health checks defined in extension method

  • The /health/extension endpoint returns the same health check results in the same format as the above health/controller endpoint, only the implementation is different. The MapEndpointHealthChecks extension method contains the /health/extension, /healthcheck, /health/ping and health/assembly endpoints:

Health check extension method

  • The extension method is added as endpoint to the http middleware pipeline:

Add health check extension method as endpoint to the http pipeline

Code: https://github.com/sztrelcsikzoltan/application-health-checks/commit/8529747653e4cebb3771ed2b69591bae351046fe

 
 
➡️ Add SQL server health checks defined in extension method

  • The health check in the AddSqlServerCheckThroughSqlCommand class uses SqlCommand to check the availability of the database server:

SqlServerHealthCheckThroughSqlCommand class

  • The health check in the AddSqlServerCheckThroughDbContext class uses DbContext of Entity Framework to check the availability of the database server.

  • It implements the IHealthCheck interface with the CheckHealthAsync (framework Microsoft.AspNetCore.App, assembly: Microsoft. AspNetCore.Diagnostics.HealthChecks.Abstractions), which returns Task, which struct type represents the results of a health check:

SqlServerHealthCheckThroughDbContext class

  • Finally, we create extension methods to add these health checks as endpoints, adding them to the IHealthCheckBuilder interface (framework: Microsoft.AspNetCore.App, assembly: Microsoft.Extensions.Diagnostics.HealthChecks), used to register health checks). The class must be added as a scoped service to the IserviceCollection, and added as a new health check using the AddCheck extension method:

Create extension methods to add Sql server health checks

  • This way these extension methods can be added as health checks to the http pipeline, where the AddHealthChecks extension method (framework: Microsoft.AspNetCore.App, assembly: Microsoft.Extensions.Diagnostics.HealthChecks) is used to add it as HealthCheckService to the container:

Add extension methods to pipeline

Code: https://github.com/sztrelcsikzoltan/application-health-checks/commit/e957185c0f51ea4f09aceadbfdd6274e7142ffb0

 
 
➡️ Add CORS policy to the health/live endpoint

  • we specify origins (URLs) allowed to access this healtch check endpoint, using the RequireCors extension method (framework: Microsoft.AspNetCore.App, assembly: Microsoft.AspNetCore.Cors):

Add CORS policy to the health-live endpoint

Code: https://github.com/sztrelcsikzoltan/application-health-checks/commit/6bf7bb0ce983c5e52a11e2b4806e0d465f9a1876

 
 
➡️ Add a health check User Interface at /healthchecks-ui endpoint In the InvestmentManager project,

  • add package AspNetCore.HealthChecks.UI (6.0.5) to display health check information in the browser,
  • add package AspNetCore.HealthChecks.UI.InMemory.Storage (6.0.5) to store health check results in memory, and
  • add package AspNetCore.HealthChecks.UI.Client (6.0.5) that supports writing the UI response

Add packages for health check user interface

Configure HealthChecksUI as a service in Program.cs:
  • add HealthChecksUI as a service with in-memory storage

  • add health check endoint /healthui for HealthChecksUI

  • configure HealthChecksUI in appsettings.json

Add HealthChecksUI with in memory storage

  • configure HealthChecksUI in appsettings.json:

Configure HealthChecksUI in appsettings.json

  • as a result we can see the health check results at the specified /healthui endpoint:

Health check results at the specified /healthui endpoint

  • configure Health Checks UI with specific path:

Configure HealthChecksUI with specific path

  • as a result, we can see the health check results on the user interface:

Health check results on the user interface

  • if the API is not accessible, Degraded status is indicated:

Health check results with Degraded status

  • if the file path is not accessible, Unhealthy status is indicated:

Health check results with Unhealthy status

Code: https://github.com/sztrelcsikzoltan/application-health-checks/commit/6a7fc7a2680d6e7134ee1f28f08733a7781bd2fd

 
 
➡️ Limit the rate of calls made to the health/ready endpoint

  • add package AspNetCoreRateLimit (5.0.0):

Add AspNetCoreRateLimit package

  • create the RateLimit.ConfigureServices method to configure the package and the services it requires:

Create the RateLimit.ConfigureServices method

  • add and configure services required for the AspNetCoreRateLimit package:

Configure AspNetCoreRateLimit in Program.cs

  • configure IpRateLimining in appsettings.json:

Configure IpRateLimining in appsettiong.json in Program.cs

  • as a result, when we try to access the health/ready endpoint within 10 seconds, our query will be rejected with this warning:

Frequent query within 10 seconds rejected

Code: https://github.com/sztrelcsikzoltan/application-health-checks/commit/2ed61287ff7f37c6ca8f92e949055eb9e1fbb8ea

 
 
➡️ Add functionality to publish health check information

  • add package RabbitMQ.Client (5.1.1):

Add package RabbitMQ.Client

  • add package component IQueueMessage interface for queuing health check information (into QueueMessage folder):

Add IQueueMessage interface

  • add RabbitMQQueueMessage class, facilitating to send queue messages:

Add RabbitMQQueueMessage class

  • add HealthCheckQueuePublisher class containing the publishing logic:

Add HealthCheckQueuePublisher class

  • configure HealthCheckPublisher options using the Configure extension method (framework: Microsoft.AspNetCore.App, assembly: Microsoft.Extensions.Options), and add its components as a service to IServiceCollection in Program.cs:

Configure HealthCheckPublisher and its dependencies

Code: https://github.com/sztrelcsikzoltan/application-health-checks/commit/91cd79583edefc5b81e77f876e0be0a57e01a314

 
 
➡️ Add HealthCheckAlerter project

  • add package Microsoft.Extensions.Hosting (6.0.1)
  • add package Newtonsoft.Json (13.0.3)
  • add package RabbitMQ.Client (5.1.0)

Add packages to HealthCheckAlerter project

Add Worker as a hosted service in Program.cs

  • install RabbitQM on the server from PowerShell (choco install rabbitmq) and allow local firewall access
  • as a result, the HealthCheckAlerter app monitors the status of the health check messages:

HealthCheckAlerter monitors the health check messages

  • the application sends e-mail alert message if the healh status is not Healthy:

HealthCheckAlerter sends alert message

  • the health messages can be monitored in RabbitMQ Server UI:

Health messages can be monitored in RabbitMQ server UI

  • the message content can be displayed on the RabbitMQ UI:

Health messages can be displayed in RabbitMQ server UI

Code: https://github.com/sztrelcsikzoltan/application-health-checks/commit/9e424b667e6d323594f448ef52cc956292c1ed80

 
 
➡️ Add database storage for health check information

  • add package AspNetCore.HealthChecks.UI.SqlServer.Storage (6.0.5) to the InvestmentManager project:

Add health check database storage to the project

  • add connection string to HealthChecks database in appsettings.json (the third-party package will automatically create the database):

Add connection string to HealthChecks database

  • add health check UI with db storage in Program.cs; it works only if AddInMemoryStorage is not added:

Add database storage for HealthChecksUI

  • as a result, the HealthChecks database is created and the current health check information will be stored there:

HealthChecks database created

Health check history stored in database

Code: https://github.com/sztrelcsikzoltan/application-health-checks/commit/4def2954d1eddb1295054f3850c99a94c7b67bf6

 
 
➡️ Add build date information as a custom AssemblyAttribute

  • define the custom attribute BuildDateAttribute with DateTime property and to retrieve its value, using the GetCustomAttribute extension method (defined in the System.Reflection.CustomAttributeExtension class):

Define BuildDateAttribute

  • make InvestmentManager.HealthChecks as a global namespace in Program.cs, so that it will be available in the auto-generated AssembyInfo.cs file:

Make namespace HealthChecks global

  • include BuildDateAttribute as AssemblyAttribute in the project file:

Include BuildDateAttribute in the project

  • add build date of the assembly to the health/assembly endpoint in HealthCheckController.cs and EndPointHealthChecks.cs:

Add BuildDate to /health/assembly endpoint

  • as a result, the health/endpoint provides this information as well:

The /health/assembly endpoint with BuildDate information

Code: https://github.com/sztrelcsikzoltan/application-health-checks/commit/5b2f60b3bd6de7ad3834756fc93fe6d9b5aef487

 
 
Refactor HealthCheckController methods

  • move CheckHealth method into CheckHealthService class
  • move VersionInfo method into CheckHealthService class
  • declare the above methods in the ICheckHealthService interface

Define BuildDateAttribute