-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Description
The default error handler for ExceptionHandlerMiddleware
always sets the response status code to 500. It is not uncommon for BadHttpRequestException
to be thrown by requests though which detail a different (usually 4xx) status code but this will get masked by the default error handler.
While it's possible to customize the error handler via setting ExceptionHandlerOptions.ExceptionHandler
, one has to reimplement the default feature logic for returning JSON Problem Details responses manually which is quite a bit of code, e.g.:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails(options =>
{
options.CustomizeProblemDetails = static ctx =>
ctx.ProblemDetails.Extensions["requestId"] = Activity.Current?.Id ?? ctx.HttpContext.TraceIdentifier;
});
var app = builder.Builder();
if (!app.Environment.IsDevelopment())
{
// Error handling
app.UseExceptionHandler(new ExceptionHandlerOptions
{
AllowStatusCode404Response = true,
ExceptionHandler = async (HttpContext context) =>
{
// Pass-through status codes from BadHttpRequestException
var exceptionHandlerFeature = context.Features.Get<IExceptionHandlerFeature>();
var error = exceptionHandlerFeature?.Error;
if (error is BadHttpRequestException badRequestEx)
{
context.Response.StatusCode = badRequestEx.StatusCode;
}
if (context.RequestServices.GetRequiredService<IProblemDetailsService>() is { } problemDetailsService)
{
await problemDetailsService.WriteAsync(new()
{
HttpContext = context,
AdditionalMetadata = exceptionHandlerFeature?.Endpoint?.Metadata,
ProblemDetails = { Status = context.Response.StatusCode }
});
}
else if (ReasonPhrases.GetReasonPhrase(context.Response.StatusCode) is { } reasonPhrase)
{
await context.Response.WriteAsync(reasonPhrase);
}
}
});
}
app.MapGet("/throw/{statusCode?}", (int? statusCode) =>
{
throw statusCode switch
{
>= 400 and < 500 => new BadHttpRequestException(
$"{statusCode} {ReasonPhrases.GetReasonPhrase(statusCode.Value)}",
statusCode.Value),
_ => new Exception("uh oh")
};
});
app.Run();
We should consider adding support for passing through the response status code from BadHttpRequestException
in the default error handler. We can consider adding a boolean property to ExceptionHandlerOptions
to control this behavior if necessary.