• Blog
  • Implementing Health Checks in .NET Core

Implementing Health Checks in .NET Core

Implementing Health Checks in .NET Core to ensure system reliability with built-in monitoring

Publish date:
Discover more of what matters to you

Introduction to Health Checks

Health checks are a fundamental pattern in modern software architecture that help ensure system reliability and maintainability. At their core, health checks are endpoints that provide information about a system’s operational status, helping operators and monitoring tools determine whether an application is functioning correctly.

Historical Context

Before the introduction of built-in health check APIs in .NET Core, developers had to implement their own solutions, which typically involved:

  1. Creating custom endpoints (usually at /health or /ping) that would return basic status information
  2. Writing custom middleware to check various system components
  3. Implementing custom monitoring logic for each dependency
  4. Building proprietary solutions for health reporting and monitoring

Common approaches included:

  • Simple ping endpoints that returned HTTP 200 OK responses
  • Custom controllers that performed basic database connectivity tests
  • Homegrown solutions for checking external service availability
  • Manual implementation of circuit breakers and timeout logic

These solutions often lacked standardization and required significant maintenance effort. Developers would frequently create their own health check frameworks or rely on third-party libraries, leading to inconsistent implementations across different applications and teams.

Evolution to Built-in Health Checks

With the introduction of .NET Core 2.2, Microsoft incorporated health checks as a first-class feature of the framework. This marked a significant improvement over previous approaches by providing:

  • A standardized API for implementing health checks
  • Built-in middleware for processing health check requests
  • Extension points for custom health check implementation
  • Integration with common monitoring and orchestration platforms
Check out our article on creating Excel reports in .NET Core with EPPlus

Setting Up Health Checks

1. Installing Required Packages

.NET Core provides built-in support for health checks via the Microsoft.AspNetCore.Diagnostics.HealthChecks package. However, for more advanced scenarios, you might need additional packages such as:

<PackageReference Include=”Microsoft.Extensions.Diagnostics.HealthChecks” Version=”7.0.0″ />
<PackageReference Include=”AspNetCore.HealthChecks.SqlServer” Version=”6.0.2″ />
<PackageReference Include=”AspNetCore.HealthChecks.Redis” Version=”6.0.4″ />
<PackageReference Include=”AspNetCore.HealthChecks.UI” Version=”6.0.5″ />

2. Configuring Basic Health Checks

In Program.cs, configure health checks using the built-in AddHealthChecks() method:

123456789
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHealthChecks()
    .AddCheck("self", () => HealthCheckResult.Healthy())
    .AddCheck<DatabaseHealthCheck>("database");
var app = builder.Build();
app.MapHealthChecks("/health");

Implementing Custom Health Checks

For complex applications, built-in checks may not be sufficient. You can implement a custom health check by inheriting from IHealthCheck:

12345678910111213141516171819202122232425
public class DatabaseHealthCheck : IHealthCheck
{
    private readonly IConfiguration _configuration;
    public DatabaseHealthCheck(IConfiguration configuration)
    {
        _configuration = configuration;
    }
    public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context,
        CancellationToken cancellationToken = default)
    {
        try
        {
            using var connection = new SqlConnection(_configuration.GetConnectionString("DefaultConnection"));
            await connection.OpenAsync(cancellationToken);
           
            return HealthCheckResult.Healthy();
        }
        catch (Exception ex)
        {
            return HealthCheckResult.Unhealthy(ex.Message);
        }
    }
}

Adding Database Health Checks

To monitor database connectivity, use the respective database health check packages:

SQL Server

12345
builder.Services.AddHealthChecks()
    .AddSqlServer(
        connectionString: configuration.GetConnectionString("DefaultConnection"),
        name: "sql",
        tags: new[] { "db", "sql", "sqlserver" });

Redis

12345
builder.Services.AddHealthChecks()
    .AddRedis(
        redisConnectionString: configuration.GetConnectionString("Redis"),
        name: "redis",
        tags: new[] { "cache", "redis" });

Formatting Health Check Responses

For structured JSON responses, use HealthCheckOptions:

1234567891011121314151617181920
app.MapHealthChecks("/health", new HealthCheckOptions
{
    ResponseWriter = async (context, report) =>
    {
        var result = JsonSerializer.Serialize(new
        {
            status = report.Status.ToString(),
            checks = report.Entries.Select(entry => new
            {
                name = entry.Key,
                status = entry.Value.Status.ToString(),
                description = entry.Value.Description,
                data = entry.Value.Data
            })
        });
        context.Response.ContentType = "application/json";
        await context.Response.WriteAsync(result);
    }
});

Enabling UI Dashboard

To visualize health checks, use AspNetCore.HealthChecks.UI:

  1. Register the UI services:
12
builder.Services.AddHealthChecksUI()
    .AddInMemoryStorage();

2. Add the UI middleware:

1
app.UseHealthChecksUI(options => options.UIPath = "/health-ui");

Best Practices for Production

When implementing health checks in production environments, consider the following best practices:

  1. Segregate Endpoints: Provide different endpoints for different types of health checks:
  • /health/live for liveness probes
  • /health/ready for readiness probes
  • /health/deep for detailed system checks

2. Performance Considerations:

  • Cache health check results where appropriate
  • Implement timeouts for external dependency checks
  • Use async operations for all I/O operations

3. Security:

  • Protect sensitive health check endpoints
  • Consider implementing authentication for detailed health information
  • Limit the information exposed in public health check endpoints

4. Monitoring Integration:

  • Configure alerts based on health check status
  • Integrate with monitoring systems like Prometheus or Azure Monitor
  • Set up appropriate logging for health check failures

Drawing the Line

Health checks are a critical aspect of modern application monitoring. .NET Core provides a flexible and extensible framework for implementing these checks, allowing you to monitor databases, caches, external services, and application internals. By integrating health checks with a UI and following best practices, you gain better visibility into your system’s health and can ensure the reliable operation of your applications.

Remember that health checks should be designed to be lightweight and non-intrusive while still providing meaningful information about system health. Regular review and updates of health check implementations ensure they remain relevant and effective as your system evolves.

Need to Upgrade Your .NET Software?
Let’s collaborate! We can guarantee the highest quality of our .NET development services and solutions.
Book a Call

Subscribe to our newsletter and get amazing content right in your inbox.

This field is required
This field is required Invalid email address
By submitting data, I agree to the Privacy Policy

Thank you for subscribing!
See you soon... in your inbox!

confirm your subscription, make sure to check your promotions/spam folder

Subscribe to our newsletter and get amazing content right in your inbox.

You can unsubscribe from the newsletter at any time

This field is required
This field is required Invalid email address

You're almost there...

A confirmation was sent to your email

confirm your subscription, make sure to check
your promotions/spam folder