Reputation: 38407
I am using the middle-ware below to set up error pages for HTTP status codes 400 to 599. So visiting /error/400
shows a 400 Bad Request error page.
application.UseStatusCodePagesWithReExecute("/error/{0}");
[Route("[controller]")]
public class ErrorController : Controller
{
[HttpGet("{statusCode}")]
public IActionResult Error(int statusCode)
{
this.Response.StatusCode = statusCode;
return this.View(statusCode);
}
}
However, visiting /this-page-does-not-exist
results in a generic IIS 404 Not Found error page.
Is there a way to handle requests that do not match any routes? How can I handle this type of request before IIS takes over? Ideally I would like to forward the request to /error/404
so that my error controller can handle it.
In ASP.NET 4.6 MVC 5, we had to use the httpErrors section in the Web.config file to do this.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" />
<error statusCode="404" responseMode="ExecuteURL" path="/error/404/" />
</httpErrors>
</system.webServer>
</configuration>
Upvotes: 45
Views: 79680
Reputation: 2446
After working on few hours for handling 500 and 404 errors, I have implemented below given solution.
For handling 500
Server Side Errors you can use app.UseExceptionHandler
middleware but app.UseExceptionHandler
middleware only handles unhandled exceptions while 404
isn't an exception. For handling 404
errors I've designed another custom middleware which is checking response status code and if it is 404
then returning user to my custom 404
error page.
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
//Hnadle unhandled exceptions 500 erros
app.UseExceptionHandler("/Pages500");
//Handle 404 erros
app.Use(async (ctx, next) =>
{
await next();
if (ctx.Response.StatusCode == 404 && !ctx.Response.HasStarted)
{
//Re-execute the request so the user gets the error page
ctx.Request.Path = "/Pages404";
await next();
}
});
}
Note: You must add app.UseExceptionHandler("/Pages500");
middleware at the starting of your Configure
method so that it can handle exceptions from all middlewares. The custom middleware can be placed any ware before app.UseEndpoins
middleware but still, it's good to place in the beginning of Configure
method.
/Pages500
and /Pages404
urls are my custom pages, you can design for your application.
Upvotes: 3
Reputation: 65
Asp.net core 3.1 and 5
in your HomeController.cs
:
public class HomeController : Controller
{
[Route("/NotFound")]
public IActionResult PageNotFound()
{
return View();
}
}
in Startup.cs
> ConfigureServices
method:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.Use(async (context, next) =>
{
await next();
if (context.Response.StatusCode == 404)
{
context.Request.Path = "/NotFound";
await next();
}
});
app.UseHttpsRedirection();
app.UseStaticFiles();
}
Upvotes: 4
Reputation: 2073
You can use fallback in EndPoint in asp.net core Like below (inside app.UseEndpoints) and with razor pages (NotFound is a razor page in Pages folder instead controller)
endpoints.MapRazorPages();
endpoints.MapFallback( context => {
context.Response.Redirect("/NotFound");
return Task.CompletedTask;
});
Upvotes: 10
Reputation: 5202
One of the best tutorials I found is this: https://joonasw.net/view/custom-error-pages
The summary is here:
1.
First add a controller like ErrorController
then add this action to it:
[Route("404")]
public IActionResult PageNotFound()
{
string originalPath = "unknown";
if (HttpContext.Items.ContainsKey("originalPath"))
{
originalPath = HttpContext.Items["originalPath"] as string;
}
return View();
}
Note: You can add the action to another existing controller like HomeController
.
2.
Now add the PageNotFound.cshtml
view. Something like this:
@{
ViewBag.Title = "404";
}
<h1>404 - Page not found</h1>
<p>Oops, better check that URL.</p>
3.
And the important part is here. Add this code to Startup
class, inside Configure
method:
app.Use(async (ctx, next) =>
{
await next();
if(ctx.Response.StatusCode == 404 && !ctx.Response.HasStarted)
{
//Re-execute the request so the user gets the error page
string originalPath = ctx.Request.Path.Value;
ctx.Items["originalPath"] = originalPath;
ctx.Request.Path = "/error/404";
await next();
}
});
Note that it must be added before routing configs like app.UseEndpoints...
.
Upvotes: 29
Reputation: 7349
Based on this SO item, IIS gets the 404 (and therefore handles it) before it reaches UseStatusCodePagesWithReExecute
.
Have you tried this: https://github.com/aspnet/Diagnostics/issues/144? It suggests terminating the request that received a 404 so it does not go to IIS to handle. And here's the code to add to your Startup to do so:
app.Run(context =>
{
context.Response.StatusCode = 404;
return Task.FromResult(0);
});
This appears to be an IIS-only issue.
Upvotes: 9