ASP.NET Core  

Health Checks in ASP.NET Core: Building Production-Ready Monitoring Endpoints

Deploying an application successfully doesn't guarantee that it remains healthy in production. Databases become unavailable, external APIs fail, message brokers disconnect, and disk space can run low without immediately crashing the application.

ASP.NET Core includes built-in Health Checks that allow monitoring systems such as Kubernetes, Azure App Service, Docker, and load balancers to determine whether an application is healthy and ready to receive traffic. Properly implemented health checks improve reliability, reduce downtime, and enable automatic recovery when failures occur.

Rather than exposing a simple "Application is running" endpoint, this article explains how to build meaningful health checks that accurately reflect your application's health.

Note: A healthy application isn't just one that is running—it must also be able to communicate with its critical dependencies such as databases, caches, message queues, and external services.

Why Health Checks Matter

Without health checks:

  • Failed instances continue receiving traffic.

  • Deployment failures go unnoticed.

  • Load balancers cannot detect unhealthy servers.

  • Kubernetes cannot restart failed containers automatically.

  • Infrastructure teams have limited visibility into application health.

Health checks allow orchestration platforms to make intelligent decisions based on the current state of the application.

Types of Health Checks

Different health checks serve different purposes.

Health CheckPurpose
LivenessDetermines whether the application is running
ReadinessDetermines whether the application is ready to receive requests
StartupIndicates whether application initialization has completed
DependencyVerifies connectivity to databases, caches, or external services

Using separate endpoints for different health states provides more accurate monitoring.

Health Check Architecture

flowchart LR

A[Monitoring System]
B[Health Endpoint]
C{Healthy?}
D[ASP.NET Core API]
E[(SQL Server)]
F[(Redis)]
G[External API]

A --> B
B --> C
C -->|Healthy| D
C -->|Check Dependencies| E
C -->|Check Dependencies| F
C -->|Check Dependencies| G

The monitoring system periodically calls the health endpoint, which verifies both the application and its dependencies.

Registering Health Checks

Add health checks during application startup.

builder.Services.AddHealthChecks();

This registers the built-in health check infrastructure.

Exposing a Health Endpoint

Map the health endpoint.

var app = builder.Build();

app.MapHealthChecks("/health");

app.Run();

A request to /health returns the application's current health status.

Checking SQL Server

Monitor database connectivity by registering a SQL Server health check.

builder.Services.AddHealthChecks()
    .AddSqlServer(
        connectionString,
        name: "sql-server");

If SQL Server becomes unavailable, the health endpoint automatically reports the failure.

Checking Redis

Applications using distributed caching should also monitor Redis availability.

builder.Services.AddHealthChecks()
    .AddRedis(
        "localhost:6379",
        name: "redis");

This ensures the cache layer is functioning correctly before the application receives traffic.

Creating a Custom Health Check

Some application-specific dependencies require custom validation.

public class PaymentGatewayHealthCheck
    : IHealthCheck
{
    public async Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default)
    {
        var reachable = await PaymentGateway.PingAsync();

        return reachable
            ? HealthCheckResult.Healthy()
            : HealthCheckResult.Unhealthy(
                "Payment gateway unavailable.");
    }
}

Register the custom health check.

builder.Services.AddHealthChecks()
    .AddCheck<PaymentGatewayHealthCheck>(
        "payment-gateway");

Custom health checks allow monitoring of business-critical services that aren't covered by built-in providers.

Health Status Responses

ASP.NET Core reports one of three health states.

StatusMeaning
HealthyApplication and dependencies are functioning normally
DegradedApplication is operational but experiencing reduced functionality
UnhealthyCritical failures prevent normal operation

Returning a degraded state can help operations teams identify issues before complete outages occur.

Liveness vs Readiness

Understanding the difference between these endpoints is essential.

EndpointTypical Use
/health/liveVerify the application process is running
/health/readyVerify the application is ready to handle requests

For example, an application may be alive but still loading configuration or waiting for database connectivity, making it unready to serve traffic.

Monitoring with Kubernetes

A typical Kubernetes deployment uses separate probes.

livenessProbe:
  httpGet:
    path: /health/live
    port: 80

readinessProbe:
  httpGet:
    path: /health/ready
    port: 80

Liveness probes restart failed containers, while readiness probes temporarily remove unhealthy instances from service.

Common Production Mistakes

ProblemRoot Cause
Health endpoint always returns healthyDependencies not included in checks
Frequent container restartsIncorrect liveness probe configuration
Requests sent to unhealthy instancesMissing readiness endpoint
Slow health responsesExpensive dependency checks
False failuresTemporary network issues treated as critical
Poor diagnosticsGeneric health responses without meaningful details

Most monitoring problems result from incomplete or poorly designed health checks.

Best Practices

  • Separate liveness and readiness endpoints.

  • Monitor all critical dependencies.

  • Keep health checks lightweight and fast.

  • Return meaningful health status messages.

  • Use degraded status when appropriate.

  • Secure internal health endpoints when necessary.

  • Continuously monitor health trends using your observability platform.

Common Anti-Patterns

Avoid these common mistakes:

  • Returning "Healthy" without checking dependencies.

  • Running expensive database queries inside health checks.

  • Using the same endpoint for every monitoring scenario.

  • Exposing sensitive infrastructure details publicly.

  • Ignoring degraded health states.

  • Treating health checks as a replacement for application monitoring.

FAQ

Should every ASP.NET Core application expose health endpoints?

Yes. Even small applications benefit from automated monitoring and easier diagnostics during deployments and production incidents.

What's the difference between liveness and readiness?

Liveness confirms that the application process is running. Readiness confirms that the application is fully initialized and capable of serving requests.

Can health checks monitor external APIs?

Yes. Custom health checks can verify connectivity to third-party APIs, payment gateways, message brokers, or any other critical dependency.

Should health checks perform full business operations?

No. Health checks should be lightweight and verify availability rather than executing expensive or long-running business logic.

Conclusion

Health Checks are a fundamental part of building reliable ASP.NET Core applications. They provide real-time insight into application health, enable automatic recovery through orchestration platforms, and help prevent unhealthy instances from serving user requests.

By monitoring critical dependencies, separating liveness and readiness checks, and implementing meaningful custom health checks where needed, you can improve application resilience, reduce downtime, and simplify production operations across modern cloud-native environments.