dotnet / dotnet/aspnetcore

UseHealthChecks does not allow trailing slash as documented

Open
#58,369 0 comments 0 reactions 0 assignees View on GitHub
area-healthchecks
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 6h
Merged PRs (30d)
290

Description

### Is there an existing issue for this?

- [x] I have searched the existing issues

### Describe the bug

Documentation of each overload of [UseHealthChecks](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.healthcheckapplicationbuilderextensions.usehealthchecks) contains a remark that states
>If path is set to null or the empty string then the health check middleware will ignore the URL path and process all requests. **If path is set to a non-empty value, the health check middleware will process requests with a URL that matches the provided value of path case-insensitively, allowing for an extra trailing slash ('/') character.**

(emphasis mine)

However, in spite of this description, I am not able to specify a path in a way that would match request path both with and without trailing slash:
| Configured Path | Request Path | Match |
| --- | --- | --- |
| `/health-check-1` | `/health-check-1` | ✅ |
| `/health-check-1` | `/health-check-1/` | ❌ |
| `/health-check-2/` | `/health-check-2/` | ✅ |
| `/health-check-2/` | `/health-check-2` | ❌ |

I am also not sure whether the trailing slash tolerance applies to request path or the configured path based on the description. Request path seems more intuitive, though (i.e. `/health-check-1` should also match `/health-check-1/`).

### Expected Behavior

Unless I understand the documentation wrong, it should be possible to configure a single path to match a request path both with and without a trailing slash. This would align the behavior with `MapHealthChecks` which currently supports this.

If that's not possible, the documentation should be updated to reflect the actual behavior - i.e. don't mention trailing slash acceptance if it does not happen. It would also make sense to note that the behavior is different from the endpoint-based version in [UseHealthChecks vs MapHealthChecks section of Health Checks documentation](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks?view=aspnetcore-8.0#usehealthchecks-vs-maphealthchecks).

### Steps To Reproduce

1. Create a new ASP.NET Core 8 Web API with Controllers project
2. In Program.cs, add a dummy health check registration to services
```csharp
// Add services to the container.
builder.Services.AddHealthChecks().AddCheck("heart-beat", () => HealthCheckResult.Healthy());
```
3. In Program.cs, register health check middlewares with and without a trailing slash in the path
```csharp
// Configure the HTTP request pipeline.
app
.UseHealthChecks("/health-check-1")
.UseHealthChecks("/health-check-2/");
```
4. Run the application. Send requests according to the above table to observe that only `/health-check-1` and `/health-check-2/` actually respond with health data, whereas `/health-check-1/` and `/health-check-2` respond with HTTP 404 Not Found.

### Exceptions (if any)

_No response_

### .NET Version

8.0.400

### Anything else?

I have checked the code and the logic in [HealthCheckApplicationBuilderExtensions](https://github.com/dotnet/aspnetcore/blob/3f1acb59718cadf111a0a796681e3d3509bb3381/src/Middleware/HealthChecks/src/Builder/HealthCheckApplicationBuilderExtensions.cs#L225-L226) works this way because:
- For request path `/health-check-1/` and configured path `/health-check-1`, the `remaining` from `StartsWithSegments` has the value of `"/"` which is not empty.
- For request path `/health-check-2` and configured path `/health-check-2/`, the `StartsWithSegments` returns `false`.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.