aspnetcore
aspnetcore copied to clipboard
Problem details middleware ignores response status code when handling an exception.
Is there an existing issue for this?
- [X] I have searched the existing issues
Describe the bug
I tried to use problem details middleware and exception handler middleware in this manner:
builder.Services.AddExceptionHandler<MyExceptionHandler>();
builder.Services.AddProblemDetails(options =>
{
options.CustomizeProblemDetails = context =>
{
if (context.Exception is MyUserFacingException)
{
context.ProblemDetails.Details = context.Exception.Message;
}
};
});
app.UseStatusCodePages();
app.UseExceptionHandler();
If the exception handler returns true then ProblemDetailsContext.Exception is null. I think this makes sense since the handler returning true means the exception does not propagate. The problem details middleware initializes ProblemDetailsContext.ProblemDetails to whatever status code was set by the exception handling middleware.
If the exception handler returns false, then the exception is available in ProblemDetailsContext.Exception, which is good. But now the problem details middleware always initializes ProblemDetailsContext.ProblemDetails as a 500, ignoring the status code set by the exception handler middleware. And there's no way to leverage the existing defaults to re-initialize it (https://github.com/dotnet/aspnetcore/issues/47978). The actual HTTP response code is the one set by the exception handler, not the 500 shown in the problem details.
Searching the code base for uses of ProblemDetailsDefaults.Apply, the only place it's called with a null status code that would result in it defaulting to 500 is here:
https://github.com/dotnet/aspnetcore/blob/6b9bba1472da66a9f02ae3cd0f564ad6e2bb5fff/src/Http/Http.Results/src/ProblemHttpResult.cs#L24
Expected Behavior
The problem details middleware should always initialize ProblemDetailsContext.ProblemDetails using HttpContext.Response.StatusCode.
Steps To Reproduce
No response
Exceptions (if any)
No response
.NET Version
8.0.400
Anything else?
No response
My workaround is for the exception handler to always return true and pass user-facing information to problem details via HttpContext.Items.
My workaround is to take exception from IExceptionHandlerFeature:
builder.Services.Configure<ProblemDetailsOptions>(static options =>
{
options.CustomizeProblemDetails = static context =>
{
var feature = context.HttpContext.Features.Get<IExceptionHandlerFeature>();
context.ProblemDetails.Detail = feature?.Error.Message;
};
});