Skip to content

Aspnet Health Checks

DodaTech 4 min read

title: ASP.NET Core Health Checks — Complete Guide to Monitoring description: 'Learn ASP.NET Core health checks: monitoring database connectivity, external services, memory usage, custom health probes, and health check UI dashboards.' date: 2026-06-28 lastmod: 2026-06-28 weight: 31 tags: [backend, aspnet]


ASP.NET Core health checks expose application health through configurable endpoints, monitoring databases, external services, and system resources for load balancers and orchestration.

## What You'll Learn

By the end of this tutorial, you'll configure health check endpoints, create custom health checks for databases and external services, use the health check UI, and integrate with orchestration tools.

## Real-World Use

Kubernetes liveness and readiness probes hit the /health/ready endpoint. If the database is unreachable, the pod is removed from service. If the app hangs, the pod is restarted.

## Health Checks Learning Path

```mermaid
flowchart LR
  A[Logging] --> B[Health Checks]
  B --> C[Docker]
  C --> D[Deployment]
  D --> E[Next Steps]
  B --> F{You Are Here}
  style F fill:#f90,color:#fff

Basic Health Check

// Program.cs
builder.Services.AddHealthChecks();

var app = builder.Build();
app.MapHealthChecks("/health");  // GET /health returns 200 if healthy

// With options
app.MapHealthChecks("/health", new HealthCheckOptions
{
    ResponseWriter = async (context, report) =>
    {
        context.Response.ContentType = "application/json";
        var response = new
        {
            Status = report.Status.ToString(),
            Duration = report.TotalDuration.TotalMilliseconds,
            Checks = report.Entries.Select(e => new
            {
                Name = e.Key,
                Status = e.Value.Status.ToString(),
                Description = e.Value.Description
            })
        };
        await context.Response.WriteAsJsonAsync(response);
    }
});

Database Health Check

dotnet add package Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore
builder.Services.AddHealthChecks()
    .AddDbContextCheck<AppDbContext>("Database", HealthStatus.Unhealthy)
    .AddSqlServer(builder.Configuration.GetConnectionString("DefaultConnection") ?? "",
        name: "SQL Server",
        failureStatus: HealthStatus.Unhealthy,
        tags: ["db", "sql"]);

Custom Health Check

public class ExternalApiHealthCheck : IHealthCheck
{
    private readonly HttpClient _httpClient;
    public ExternalApiHealthCheck(HttpClient httpClient) => _httpClient = httpClient;
    
    public async Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken ct = default)
    {
        try
        {
            var response = await _httpClient.GetAsync("https://api.external.com/health", ct);
            if (response.IsSuccessStatusCode)
                return HealthCheckResult.Healthy("External API is reachable");
            return HealthCheckResult.Degraded($"External API returned {response.StatusCode}");
        }
        catch (Exception ex)
        {
            return HealthCheckResult.Unhealthy("External API is unreachable", ex);
        }
    }
}
// Registration
builder.Services.AddHttpClient<ExternalApiHealthCheck>();
builder.Services.AddHealthChecks()
    .AddCheck<ExternalApiHealthCheck>("External API", tags: ["external"]);

Liveness and Readiness

// Readiness: app is ready to serve traffic
app.MapHealthChecks("/health/ready", new HealthCheckOptions
{
    Predicate = check => check.Tags.Contains("ready"),  // Only checks tagged "ready"
    AllowCachingResponses = false
});
// Liveness: app is running
app.MapHealthChecks("/health/live", new HealthCheckOptions
{
    Predicate = _ => false,  // Always healthy (just checks the process is alive)
    AllowCachingResponses = false
});

Health Check UI

dotnet add package AspNetCore.HealthChecks.UI
dotnet add package AspNetCore.HealthChecks.UI.InMemory.Storage
dotnet add package AspNetCore.HealthChecks.UI.Client
builder.Services.AddHealthChecksUI(options =>
{
    options.SetEvaluationTimeInSeconds(10);
    options.MaximumHistoryEntriesPerEndpoint(50);
}).AddInMemoryStorage();

var app = builder.Build();
app.MapHealthChecksUI(options => options.UIPath = "/health-ui");
// Access /health-ui for the dashboard

Common Mistakes

1. Including Heavy Checks in Liveness Probe

Liveness probes should be lightweight (process alive). Heavy checks (DB connectivity) belong in readiness.

2. Caching Health Check Results

Default caching may return stale results. Set AllowCachingResponses = false for readiness probes.

3. Not Tagging Health Checks

Tags help group checks: "ready" for readiness, "db" for database checks, "external" for third-party services.

4. Ignoring Degraded Status

Health check can return Healthy, Degraded (partial failure), or Unhealthy. Orchestrators decide action per status.

5. Not Securing Health Endpoints

Health endpoints reveal internal details. Restrict to internal networks or require authorization.

Practice Questions

1. What is the purpose of health checks?

Health checks expose application status for load balancers, orchestrators (Kubernetes), and monitoring systems.

2. What is the difference between liveness and readiness?

Liveness checks if the app process is running. Readiness checks if the app can serve requests (DB connected).

3. How do you create a custom health check?

Implement IHealthCheck interface with CheckHealthAsync method returning HealthCheckResult.

4. How do Kubernetes probes work with health checks?

Kubernetes calls /health/live for liveness and /health/ready for readiness. Unhealthy responses trigger pod actions.

5. Challenge: Create health checks for database, Redis, and an external API with a UI dashboard.

builder.Services.AddHealthChecks()
    .AddDbContextCheck<AppDbContext>("Database")
    .AddRedis("localhost:6379", "Redis")
    .AddCheck<ExternalApiHealthCheck>("External API");
builder.Services.AddHealthChecksUI().AddInMemoryStorage();

FAQ

What status code does a healthy check return?

200 OK. Unhealthy returns 503 Service Unavailable.

Can health checks have custom responses?

Yes. Use the ResponseWriter delegate to return JSON, XML, or custom formats.

How often should health checks run?

Liveness: every 10-30 seconds. Readiness: every 5-10 seconds. Kubernetes has configurable intervals.

Do health checks affect performance?

Health checks are lightweight. Avoid expensive operations (complex queries) in health check endpoints.

Should health checks be authenticated?

In production, secure health endpoints. In internal networks, authentication may not be needed.

Mini Project: Complete Health Check Setup

Configure liveness, readiness, database, and external API health checks.

builder.Services.AddHealthChecks()
    .AddDbContextCheck<AppDbContext>(tags: ["ready"])
    .AddCheck<ExternalApiHealthCheck>("Payment Gateway", tags: ["ready", "external"]);
app.MapHealthChecks("/health/ready", new() {
    Predicate = c => c.Tags.Contains("ready"),
    ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
app.MapHealthChecks("/health/live", new() { Predicate = _ => false });

What's Next

ASP.NET Core Docker ASP.NET Core Deployment

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro