I'm trying to get my 404s working correctly but can't figure out how to get it quite right.
Initially I set my the following in my Statup Configure method:
app.UseMvc(routes =>
{
// routing here
});
app.Use((context, next) =>
{
context.Response.StatusCode = 404;
return next();
});
app.UseStatusCodePagesWithRedirects("/error/{0}");
Which redirected to a page where I showed the error. However the status codes were 302 > 200
. I set the /error/{code}
action to return the relevant status code, so now I have 302 > 404
which (due to the 302 redirect) makes it look as though the /error/404
page doesn't exist (which it does).
What I want to do is to return the error page without the redirect, so that attempting to request /doesntexist
will return 404 and display the error page.
The other thing I tried is to use app.UseStatusCodePagesWithReExecute("/error/{0}");
which does return a 404 without changing the url but displays only a blank page rather than my error page
404s should not always be redirected. 404s should not be redirected globally to the home page. 404s should only be redirected to a category or parent page if that's the most relevant user experience available. It's okay to serve a 404 when the page doesn't exist anymore (crazy, I know).
There are several reasons why you might be getting an HTTP 404 code: One typical trigger for an error 404 message is when the page has been deleted from the website. The page was moved to another URL and the redirection was done incorrectly. You entered an incorrect URL address.
In my app, I'm doing it like this:
// custom 404 and error page - this preserves the status code (ie 404)
app.UseStatusCodePagesWithReExecute("/Home/Error/{0}");
My HomeController has this action method
public IActionResult Error(int statusCode)
{
if (statusCode == 404)
{
var statusFeature = HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
if (statusFeature != null)
{
log.LogWarning("handled 404 for url: {OriginalPath}", statusFeature.OriginalPath);
}
}
return View(statusCode);
}
and my view is like this:
@model int
@{
switch (Model)
{
case 400:
ViewData["Icon"] = "fa fa-ban text-danger";
ViewData["Title"] = "Bad Request";
ViewData["Description"] = "Your browser sent a request that this server could not understand.";
break;
case 401:
ViewData["Icon"] = "fa fa-ban text-danger";
ViewData["Title"] = "Unauthorized";
ViewData["Description"] = "Sorry, but the page requires authentication.";
break;
case 403:
ViewData["Icon"] = "fa fa-exclamation-circle text-danger";
ViewData["Title"] = "Forbidden";
ViewData["Description"] = "Sorry, but you don't have permission to access this page.";
break;
case 404:
ViewData["Icon"] = "fa fa-exclamation-circle text-danger";
ViewData["Title"] = "Page Not Found";
ViewData["Description"] = "Sorry, but the page you were looking for can't be found.";
break;
case 500:
default:
ViewData["Icon"] = "fa fa-exclamation-circle text-danger";
ViewData["Title"] = "Unexpected Error";
ViewData["Description"] = "Well, this is embarrassing. An error occurred while processing your request. Rest assured, this problem has been logged and hamsters have been released to fix the problem.";
break;
}
}
<div class="jumbotron text-center">
<header>
<h1><span aria-hidden="true" class="@ViewData["Icon"]"></span> @ViewData["Title"]</h1>
</header>
<p>@ViewData["Description"]</p>
<a class="btn btn-primary btn-lg" href="@Url.RouteUrl("/")"><span aria-hidden="true" class="fa fa-home"></span> Site Home</a>
</div>
as mentioned by @khellang, the order of middleware is important, and this should be before app.UseMvc
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With