I'm trying to write some middleware that will intercept a custom exception and update the response status as appropriate. For example, if the exception is a custom NotFoundException, it should update the response StatusCode to 404.
This seems to all work correctly, however when I also add UseStatusCodePagesWithReExecute to the pipeline, the site doesn't show the 404 error page, instead it just shows the browser default 404 error. If I go to any page that is truly not found, then the status code pages work as expected.
The use-case is that I have a page that takes a parameter as a look-up value. If that value isn't found, I want to throw a NotFoundException, have the exception handler middleware catch it and update the status code to 404, and then have the status code pages show the friendly error page.
So far the only workaround I've found is to redirect to the appropriate error page manually in the exception handler middleware and skip UseStatusCodePagesWithReExecute for this use-case. That works, except that I'd rather not do the full redirect and instead have it keep the url of the original request and just show the content from the 404 page.
This is the exception handler middleware I'm using:
public class ExceptionHandlerMiddleware{ private readonly RequestDelegate _next; public ExceptionHandlerMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext context) { try { await _next(context); } catch (Exception ex) { await ConvertException(context, ex); } } private static Task ConvertException(HttpContext context, Exception exception) { HttpStatusCode httpStatusCode = HttpStatusCode.InternalServerError; context.Response.ContentType = "application/json"; var result = string.Empty; switch (exception) { case BadRequestException badRequestException: httpStatusCode = HttpStatusCode.BadRequest; result = badRequestException.Message; break; case NotFoundException: httpStatusCode = HttpStatusCode.NotFound; break; case Exception: httpStatusCode = HttpStatusCode.BadRequest; break; } context.Response.StatusCode = (int)httpStatusCode; context.SetEndpoint(null); if (result == string.Empty) { result = JsonSerializer.Serialize(new { error = exception.Message }); } Log.Error(exception, "Unhandled Exception"); return Task.CompletedTask; }}And here is the Blazor component code that is throwing the exception. I'm using refit to call an API and get the StatusCode from the result.
[Parameter]public string? CompanyName { get; set; }protected override async Task OnInitializedAsync(){ if (!string.IsNullOrEmpty(CompanyName)) { var c = await CompanyClient.GetCompanyByName(CompanyName); if (c.StatusCode == System.Net.HttpStatusCode.NotFound) { throw new NotFoundException("Company", new { CompanyName }); } else { _company = c.Content!.Name; } } }I've tried changing the order of the pipeline to see if that makes a difference, but so far it seems to behave the same way in any order. I would expect these two pipeline steps to essentially pass off from one to the next to convert the response code and then show the appropriate content for it.