Custom error page with 500 status code in .NET 6
Setting a custom error page in .NET 6 seems trivial. Just find a documentation and copy a code from there. It works, but even if everything looks great at first glance, there is a tiny detail which is not always desired - the error page returns 200 HTTP status code. What if we want to return 500 code?
To be or not to be
How it should be? What is the correct way in this case? 200 or 500 code? For sure, Microsoft picks the 200's side. Of course, it makes sense. The page itself is returned correctly, and the error should be handled in the backend, so why confuse the browser additionally? What is the advantage of having a 500 code? I can think of one. I want to have it logged in a tool like Application Insights so I can easily filter failed requests. But at the end, all these don't matter.
Requirement
It is good to follow best practices. However, sometimes the work must be done. And in this case, we want to have a custom error page with 500 HTTP code. Now it seems, it is not that trivial. A developer must dig deeper.
Standard way
Following the documentation, to show a custom error page, this line needs to be added to the Startup.cs file:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/error.html");
app.UseHsts();
}
This redirects a request to the static error.html file underneath the wwwroot folder and returns a 200 HTTP code.Static file + 500 code
How to configure it to return a 500 status code then? Is there any boolean flag option for this middleware? Not exactly.
What needs to be done is to implement a custom configuration for UseExceptionHandler middleware where it is instructed to find static HTML in the file system and set InternalServerError code in the response.
app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.ContentType = "text/html";
var filePath = Path.Combine(env.WebRootPath, "error.html");
var htmlContent = await File.ReadAllTextAsync(filePath);
await context.Response.WriteAsync(htmlContent);
});
});
And that's it. I know, it looks easy. But it wasn't easy to find out how to do it. However, satisfaction at the end is priceless.