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
- Most code and health check examples are based on the Pluralsight course ASP.NET Core 3 Health Checks created by Rag Dhiman (https://app.pluralsight.com/profile/author/rag-dhiman), whereas all applications are updated to target .NET framework 6.0
➡️ Liveness health check using the MapHealthChecks extension method (framework: Microsoft.AspNetCore.App, assembly: Microsoft.Extensions.Diagnostics.HealthChecks) Endpoint: /health
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
➡️ 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"
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 endpoint health check, using the AddUrlGroup extension method (NuGet package AspNetCore.HealthChecks.Uris, assembly: HealthChecks.Uris)
Health check name: "Stock Index API Health Check"
➡️ 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
➡️ 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 separate endpoints for differently tagged health checks:
- /health/live endpoint:
➡️ Customize the content and format of health check responses:
- /health/ready endpoint:
➡️ Add file path write health check using a class instance
- health check name: "File Path Health Check class"
➡️ Add file path write health check using the extension method AddFilePathWrite
- health check name: "File Path Health Check extension"
➡️ 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:
- configure JWT token request in Postman:
- JWT token received in Postman:
- Request to health check endpoint successful with the JWT token:
➡️ 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:
- 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:
- the final result is formatted by TextWriter using the enum type Formating option Indented (package: NewtonSoft.Json, assembly: Newtonsoft.Json):
- as a result each child object appears in a new line indented:
- if the StockIndexWebService API is not available, the endpoint returns Degraded Status for this health check, along with Exception information:
- 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:
- the /healthcheck endpoint redirects to the ./health/controller endpoint:
- the /health/ping endpoint returns 200 (OK) status code to indicate that the dependency app is reachable:
- the /health/assembly endpoint returns assembly-related information, such as Application name, BuildDate, ProductVersion, AssembyVersion:
- 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):
➡️ 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:
- The extension method is added as endpoint to the http middleware pipeline:
➡️ 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:
-
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:
- 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:
- 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 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 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 HealthChecksUI as a service with in-memory storage
-
add health check endoint /healthui for HealthChecksUI
-
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:
- configure Health Checks UI with specific path:
- as a result, we can see the health check results on the user interface:
- if the API is not accessible, Degraded status is indicated:
- if the file path is not accessible, Unhealthy status is indicated:
➡️ Limit the rate of calls made to the health/ready endpoint
- add package AspNetCoreRateLimit (5.0.0):
- create the RateLimit.ConfigureServices method to configure the package and the services it requires:
- add and configure services required for the AspNetCoreRateLimit package:
- configure IpRateLimining in appsettings.json:
- as a result, when we try to access the health/ready endpoint within 10 seconds, our query will be rejected with this warning:
➡️ Add functionality to publish health check information
- add package RabbitMQ.Client (5.1.1):
- add package component IQueueMessage interface for queuing health check information (into QueueMessage folder):
- add RabbitMQQueueMessage class, facilitating to send queue messages:
- add HealthCheckQueuePublisher class containing the publishing logic:
- 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:
➡️ 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 Worker.cs to implement a long-running IHostedService (https://github.com/sztrelcsikzoltan/application-health-checks/blob/master/InvestmentManager/HealthCheckAlerter/Worker.cs)
- 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:
- the application sends e-mail alert message if the healh status is not Healthy:
- the health messages can be monitored in RabbitMQ Server UI:
- the message content can be displayed on the RabbitMQ UI:
➡️ Add database storage for health check information
- add package AspNetCore.HealthChecks.UI.SqlServer.Storage (6.0.5) to the InvestmentManager project:
- add connection string to HealthChecks database in appsettings.json (the third-party package will automatically create the database):
- add health check UI with db storage in Program.cs; it works only if AddInMemoryStorage is not added:
- as a result, the HealthChecks database is created and the current health check information will be stored there:
➡️ 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):
- make InvestmentManager.HealthChecks as a global namespace in Program.cs, so that it will be available in the auto-generated AssembyInfo.cs file:
- include BuildDateAttribute as AssemblyAttribute in the project file:
- add build date of the assembly to the health/assembly endpoint in HealthCheckController.cs and EndPointHealthChecks.cs:
- as a result, the health/endpoint provides this information as well:
Refactor HealthCheckController methods
- move CheckHealth method into CheckHealthService class
- move VersionInfo method into CheckHealthService class
- declare the above methods in the ICheckHealthService interface
- register the CheckHealthService as a transient service Code: https://github.com/sztrelcsikzoltan/application-health-checks/commit/291080e7ba4325f491dc28caa6ac48b2c248f174