Adding Health Checks - Building a Sample API in C# Course
Developing and testing RESTful APIs in C# using ASP.NET Core is a practical skill for any modern backend developer. In his tutorial video on "Adding Health Checks - Building a Sample API in C# Course", Tim Corey walks through building a sample API with integrated health checks. This article, based solely on Tim's transcript, explains the entire process step by step, covering key points like the use of public async Task, int id, var app, and other HTTP request methods.
Let's take a deeper look at how Tim Corey sets up health checks in a C# API project using Visual Studio Code.
Introduction to Sample API and Health Checks
Tim explains that a sample API is a powerful tool when learning web development. It allows developers to simulate API calls using GET, POST, PUT, and DELETE methods, with appropriate request data and status codes. The API Tim builds supports:
Sample data with a data model
RESTful behaviors for API requests
JSON format responses
Health checks
- Deployment as both Docker containers and web applications
Installing Health Checks Package
Tim opens the project in Visual Studio Code and right-clicks on Dependencies to manage NuGet packages. He searches for and installs the AspNetCore.HealthChecks.UI.Client package. This enables the app to support two types of health checks.
Creating Health Check Classes
Tim adds a new folder named HealthChecks inside the API project folder. Here, he creates multiple classes implementing the IHealthCheck interface, each representing a different status: healthy, degraded, unhealthy, and random.
HealthyHealthCheck.cs
This class returns a HealthCheckResult.Healthy using a public async Task
return Task.FromResult(HealthCheckResult.Healthy("This is a test healthy service."));
return Task.FromResult(HealthCheckResult.Healthy("This is a test healthy service."));
This simulates a healthy status, useful for testing how your front end handles a stable service.
DegradedHealthCheck.cs
return Task.FromResult(HealthCheckResult.Degraded("This is a test degraded service."));
return Task.FromResult(HealthCheckResult.Degraded("This is a test degraded service."));
This check returns a degraded service response. It's a simple way to simulate partial failure or performance issues.
UnhealthyHealthCheck.cs
return Task.FromResult(HealthCheckResult.Unhealthy("This is a test unhealthy service."));
return Task.FromResult(HealthCheckResult.Unhealthy("This is a test unhealthy service."));
This mimics a failed service, simulating cases where you would expect a 500 HTTP status code or return NotFound().
RandomHealthCheck.cs
This health check uses a random integer to simulate one of the three states:
int randomResult = Random.Shared.Next(1, 4);
return randomResult switch
{
1 => Task.FromResult(HealthCheckResult.Healthy("This is a test random service.")),
2 => Task.FromResult(HealthCheckResult.Degraded("This is a test random service.")),
3 => Task.FromResult(HealthCheckResult.Unhealthy("This is a test random service.")),
_ => Task.FromResult(HealthCheckResult.Healthy("This is a test random service."))
};
int randomResult = Random.Shared.Next(1, 4);
return randomResult switch
{
1 => Task.FromResult(HealthCheckResult.Healthy("This is a test random service.")),
2 => Task.FromResult(HealthCheckResult.Degraded("This is a test random service.")),
3 => Task.FromResult(HealthCheckResult.Unhealthy("This is a test random service.")),
_ => Task.FromResult(HealthCheckResult.Healthy("This is a test random service."))
};
Tim emphasizes this is useful for testing behavior under variable conditions.
Registering Health Checks in Startup Configuration
Tim adds a new static class HealthChecksConfig.cs in the Startup or configuration folder. This class includes two static methods:
AddAllHealthChecks()
services.AddHealthChecks()
.AddCheck<RandomHealthCheck>("random", tags: new[] { "random" })
.AddCheck<HealthyHealthCheck>("healthy", tags: new[] { "healthy" })
.AddCheck<DegradedHealthCheck>("degraded", tags: new[] { "degraded" })
.AddCheck<UnhealthyHealthCheck>("unhealthy", tags: new[] { "unhealthy" });
services.AddHealthChecks()
.AddCheck<RandomHealthCheck>("random", tags: new[] { "random" })
.AddCheck<HealthyHealthCheck>("healthy", tags: new[] { "healthy" })
.AddCheck<DegradedHealthCheck>("degraded", tags: new[] { "degraded" })
.AddCheck<UnhealthyHealthCheck>("unhealthy", tags: new[] { "unhealthy" });
This registers all the health checks for dependency injection in the services container of ASP.NET Core.
MapAllHealthChecks()
app.MapHealthChecks("/health");
app.MapHealthChecks("/health");
This creates a single endpoint /health that evaluates all services together. If any are unhealthy, the entire check returns unhealthy.
Creating Specific Health Endpoints
To test individual components, Tim maps each health check by tag:
app.MapHealthChecks("/health/healthy", new HealthCheckOptions {
Predicate = x => x.Tags.Contains("healthy")
});
app.MapHealthChecks("/health/healthy", new HealthCheckOptions {
Predicate = x => x.Tags.Contains("healthy")
});
He repeats this for /health/degraded, /health/unhealthy, and /health/random. Each allows developers to test specific behaviors and how their frontend reacts to them.
When visiting /health/random, the output changes between "healthy", "degraded", and "unhealthy" based on the random result.
Adding UI Support for Health Checks
Tim enhances the endpoints by enabling a UI response for each health check route. This provides a JSON output:
app.MapHealthChecks("/healthui", new HealthCheckOptions
{
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
app.MapHealthChecks("/healthui", new HealthCheckOptions
{
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
This allows inspection of each health check with data like duration, tags, and status. Tim then creates UI versions for each health endpoint:
/healthui/healthy
/healthui/degraded
/healthui/unhealthy
- /healthui/random
Each responds with a detailed JSON format, ideal for RESTful APIs and testing from mobile devices or web pages.
Wrapping Up the API Project
Tim highlights that even with these features, Program.cs is still only 21 lines long. He attributes this to:
Good project folder structure
Keeping models in the Models folder
Placing endpoints and controllers in their own folders
- Using async Task methods for each health check class
He also emphasizes how useful this sample API is in production environments for simulating latency or faults before deployment.
"We can do a lot more testing with this API beyond just making GET calls to it," Tim concludes.
What Comes Next
Tim previews the next lesson where he'll add simulated slowdowns (e.g., 5-second delays) and errors like return NotFound() or return BadRequest() to test API behavior even further.
Conclusion
In this video tutorial, Tim Corey methodically walks through building a minimal API with integrated health checks using ASP.NET Core. Key components include:
Health check classes (Healthy, Degraded, Unhealthy, Random)
Dependency injection via AddHealthChecks()
Mapping endpoints using MapHealthChecks()
- Supporting structured JSON responses
This approach makes it easier to validate REST APIs, simulate failures, and strengthen web applications for both development and production environments.