Skip to content

Commit 34b3eae

Browse files
committed
Add health checks module
Fixes #76 Add health checks module to the application. * **Add Health Check Packages**: Add `Microsoft.Extensions.Diagnostics.HealthChecks`, `AspNetCore.HealthChecks.Npgsql`, and `AspNetCore.HealthChecks.Redis` package references to `complete/Api/Api.csproj`. * **Add Health Check Services**: Add health check services for database, redis cache, and external service in `complete/Api/Program.cs`. * **Add Health Check Endpoints**: Add health check endpoints for `/health` and `/alive` in `complete/Api/Program.cs`. * **Considerations for Non-Development Environments**: Add considerations for non-development environments in `MapDefaultEndpoints` method in `complete/ServiceDefaults/Extensions.cs`. * **Documentation**: Add `workshop/10-health-checks.md` to explain the health checks module and include instructions for students to update the application with health checks. Reference relevant documentation and include information on the HealthChecksUI sample. --- For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/dotnet-presentations/dotnet-aspire-workshop/issues/76?shareId=XXXX-XXXX-XXXX-XXXX).
1 parent 2f62f1c commit 34b3eae

File tree

4 files changed

+179
-0
lines changed

4 files changed

+179
-0
lines changed

complete/Api/Api.csproj

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.2" />
1010
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.0" />
1111
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.0" />
12+
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="6.0.0" />
13+
<PackageReference Include="AspNetCore.HealthChecks.Npgsql" Version="6.0.0" />
14+
<PackageReference Include="AspNetCore.HealthChecks.Redis" Version="6.0.0" />
1215
</ItemGroup>
1316
<ItemGroup>
1417
<ProjectReference Include="..\ServiceDefaults\ServiceDefaults.csproj" />

complete/Api/Program.cs

+14
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using OpenTelemetry.Trace;
33
using Api.Data;
44
using Microsoft.EntityFrameworkCore;
5+
using Microsoft.Extensions.Diagnostics.HealthChecks;
56

67
var builder = WebApplication.CreateBuilder(args);
78

@@ -21,6 +22,12 @@
2122
builder.Services.AddOpenTelemetry()
2223
.WithMetrics(m => m.AddMeter("NwsManagerMetrics"));
2324

25+
// Add health check services for database, redis cache, and external service
26+
builder.Services.AddHealthChecks()
27+
.AddNpgSql(builder.Configuration.GetConnectionString("DefaultConnection"), name: "postgresql")
28+
.AddRedis("localhost:6379", name: "redis")
29+
.AddUrlGroup(new Uri("https://api.weather.gov/"), name: "weatherapi");
30+
2431
var app = builder.Build();
2532

2633
app.MapDefaultEndpoints();
@@ -30,4 +37,11 @@
3037
// Map the endpoints for the API
3138
app.MapApiEndpoints();
3239

40+
// Add health check endpoints for /health and /alive
41+
app.MapHealthChecks("/health");
42+
app.MapHealthChecks("/alive", new HealthCheckOptions
43+
{
44+
Predicate = r => r.Tags.Contains("live")
45+
});
46+
3347
app.Run();

complete/ServiceDefaults/Extensions.cs

+45
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,51 @@ public static WebApplication MapDefaultEndpoints(this WebApplication app)
124124
Predicate = r => r.Tags.Contains("live")
125125
});
126126
}
127+
else
128+
{
129+
// Considerations for non-development environments
130+
app.MapHealthChecks("/health", new HealthCheckOptions
131+
{
132+
Predicate = _ => true,
133+
ResponseWriter = async (context, report) =>
134+
{
135+
context.Response.ContentType = "application/json";
136+
var result = JsonSerializer.Serialize(new
137+
{
138+
status = report.Status.ToString(),
139+
checks = report.Entries.Select(e => new
140+
{
141+
name = e.Key,
142+
status = e.Value.Status.ToString(),
143+
exception = e.Value.Exception?.Message,
144+
duration = e.Value.Duration.ToString()
145+
})
146+
});
147+
await context.Response.WriteAsync(result);
148+
}
149+
});
150+
151+
app.MapHealthChecks("/alive", new HealthCheckOptions
152+
{
153+
Predicate = r => r.Tags.Contains("live"),
154+
ResponseWriter = async (context, report) =>
155+
{
156+
context.Response.ContentType = "application/json";
157+
var result = JsonSerializer.Serialize(new
158+
{
159+
status = report.Status.ToString(),
160+
checks = report.Entries.Select(e => new
161+
{
162+
name = e.Key,
163+
status = e.Value.Status.ToString(),
164+
exception = e.Value.Exception?.Message,
165+
duration = e.Value.Duration.ToString()
166+
})
167+
});
168+
await context.Response.WriteAsync(result);
169+
}
170+
});
171+
}
127172

128173
return app;
129174
}

workshop/10-health-checks.md

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Health Checks
2+
3+
## Introduction
4+
5+
In this module, we will add health checks to our application. Health checks are used to determine the health of an application and its dependencies. They can be used to monitor the health of the application and its dependencies, and to determine if the application is ready to accept traffic.
6+
7+
## Adding Health Checks
8+
9+
### Step 1: Add Health Check Packages
10+
11+
First, we need to add the necessary packages to our project. Open the `complete/Api/Api.csproj` file and add the following package references:
12+
13+
```xml
14+
<ItemGroup>
15+
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="6.0.0" />
16+
<PackageReference Include="AspNetCore.HealthChecks.Npgsql" Version="6.0.0" />
17+
<PackageReference Include="AspNetCore.HealthChecks.Redis" Version="6.0.0" />
18+
</ItemGroup>
19+
```
20+
21+
### Step 2: Add Health Check Services
22+
23+
Next, we need to add the health check services to our application. Open the `complete/Api/Program.cs` file and add the following code:
24+
25+
```csharp
26+
builder.Services.AddHealthChecks()
27+
.AddNpgSql(builder.Configuration.GetConnectionString("DefaultConnection"), name: "postgresql")
28+
.AddRedis("localhost:6379", name: "redis")
29+
.AddUrlGroup(new Uri("https://api.weather.gov/"), name: "weatherapi");
30+
```
31+
32+
### Step 3: Add Health Check Endpoints
33+
34+
Now, we need to add the health check endpoints to our application. Open the `complete/Api/Program.cs` file and add the following code:
35+
36+
```csharp
37+
app.MapHealthChecks("/health");
38+
app.MapHealthChecks("/alive", new HealthCheckOptions
39+
{
40+
Predicate = r => r.Tags.Contains("live")
41+
});
42+
```
43+
44+
### Step 4: Add Considerations for Non-Development Environments
45+
46+
Finally, we need to add considerations for non-development environments. Open the `complete/ServiceDefaults/Extensions.cs` file and update the `MapDefaultEndpoints` method as follows:
47+
48+
```csharp
49+
public static WebApplication MapDefaultEndpoints(this WebApplication app)
50+
{
51+
if (app.Environment.IsDevelopment())
52+
{
53+
app.MapHealthChecks("/health");
54+
app.MapHealthChecks("/alive", new HealthCheckOptions
55+
{
56+
Predicate = r => r.Tags.Contains("live")
57+
});
58+
}
59+
else
60+
{
61+
app.MapHealthChecks("/health", new HealthCheckOptions
62+
{
63+
Predicate = _ => true,
64+
ResponseWriter = async (context, report) =>
65+
{
66+
context.Response.ContentType = "application/json";
67+
var result = JsonSerializer.Serialize(new
68+
{
69+
status = report.Status.ToString(),
70+
checks = report.Entries.Select(e => new
71+
{
72+
name = e.Key,
73+
status = e.Value.Status.ToString(),
74+
exception = e.Value.Exception?.Message,
75+
duration = e.Value.Duration.ToString()
76+
})
77+
});
78+
await context.Response.WriteAsync(result);
79+
}
80+
});
81+
82+
app.MapHealthChecks("/alive", new HealthCheckOptions
83+
{
84+
Predicate = r => r.Tags.Contains("live"),
85+
ResponseWriter = async (context, report) =>
86+
{
87+
context.Response.ContentType = "application/json";
88+
var result = JsonSerializer.Serialize(new
89+
{
90+
status = report.Status.ToString(),
91+
checks = report.Entries.Select(e => new
92+
{
93+
name = e.Key,
94+
status = e.Value.Status.ToString(),
95+
exception = e.Value.Exception?.Message,
96+
duration = e.Value.Duration.ToString()
97+
})
98+
});
99+
await context.Response.WriteAsync(result);
100+
}
101+
});
102+
}
103+
104+
return app;
105+
}
106+
```
107+
108+
## References
109+
110+
For more information on health checks, see the following documentation:
111+
112+
- [Health Checks in .NET Aspire](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/health-checks)
113+
- [Health Checks in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks)
114+
115+
## HealthChecksUI Sample
116+
117+
You can also add a UI for your health checks using the [HealthChecksUI sample](https://github.com/dotnet/aspire-samples/tree/main/samples/HealthChecksUI). This sample shows how to add the UI as a container and provides a link to the sample for those who are interested.

0 commit comments

Comments
 (0)