404- Page Not Found Handling in ASP.NET Core

Types of 404 Error

In ASP.NET Core there are 2 types of 404 errors that could happen
1: Resource with the specified ID does not exit. 
2: The provided URL does not match any route in our application. 


Handling non-success http status codes

To handle non-success http status codes such as 404 for example, we can use the following 3 built-in asp.net core middleware components.

1. UseStatusCodePages
2. UseStatusCodePagesWithRedirects
3. UseStatusCodePagesWithReExecute


1. UseStatusCodePages Middleware

This is the least useful as it simply just shows default error text on the screen. To use it in an application, plug it into the HTTP processing pipeline as shown below.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseStatusCodePages();
    }

    app.UseStaticFiles();

    app.UseMvc(routes =>
    {
        routes.MapRoute("default""{controller=Home}/{action=Index}/{id?}");
    });
}

2. UseStatusCodePagesWithRedirects Middleware

To intercept these non-success HTTP status codes and return a custom error view, we can either use UseStatusCodePagesWithRedirects middleware or UseStatusCodePagesWithReExecute middleware.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseStatusCodePagesWithRedirects("/Error/{0}");
    }

    app.UseStaticFiles();

    app.UseMvc(routes =>
    {
        routes.MapRoute("default""{controller=Home}/{action=Index}/{id?}");
    });
}


ErrorController :- 

public class ErrorController : Controller
{
    // If there is 404 status code, the route path will become Error/404
    [Route("Error/{statusCode}")]
    public IActionResult HttpStatusCodeHandler(int statusCode)
    {
        switch (statusCode)
        {
            case 404:
                ViewBag.ErrorMessage = "Sorry, the resource you requested could not be found";
                break;
        }

        return View("NotFound");
    }
}

NotFound View
@{
    ViewBag.Title = "Not Found";
}

<h1>@ViewBag.ErrorMessage</h1>

<a asp-action="index" asp-controller="home">
    Click here for home page
</a>

At this point, if we navigate to http://localhost/foo/bar we see the following custom 404 error view NotFound.cshtml as expected.

2. UseStatusCodePagesWithReExecute Middleware

To use UseStatusCodePagesWithReExecute middleware instead of UseStatusCodePagesWithRedirects middleware

REPLACE app.UseStatusCodePagesWithRedirects("/Error/{0}");
WITH app.UseStatusCodePagesWithReExecute("/Error/{0}");

There is no difference in the behavior of UseStatusCodePagesWithReExecute  & UseStatusCodePagesWithRedirects 


Diffrence Between UseStatusCodePagesWithReExecute  & UseStatusCodePagesWithRedirects?

There is a difference in request processing between this two, 

Request Processing in UseStatusCodePagesWithReExecute 
  • StatusCodePagesWithRedirects middleware intercepts request and changes it to 302, pointing it to the given error path (/Error/404) 
  • Another GET request is issued to serve the redirected request
  • URL in the address bar changes to /Error/404
  • The request flows through the pipeline and handled by the MVC middleware which ultimately returns NotFound view HTML with status code 200
  • It is returning a success status code (200). 
Request processing with UseStatusCodePagesWithReExecute
  • UseStatusCodePagesWithReExecute middleware intercepts the 404 status code and re-executes the pipeline pointing it to the URL  (/Error/404)
  • The request flows through the pipeline and handled by the MVC middleware which returns NotFound view HTML along with status code 200
  • As the response flows out to the client, it passes through UseStatusCodePagesWithReExecute middleware which uses the HTML response but replaces the 200 status code with the original 404 status code.
  • This is a clever piece of middleware. As the name implies it re-executes the pipeline keeping the correct (404) status code. It just returns the custom view (NotFound) HTML
  • As it is just re-executing the pipeline and not issuing a redirect request, also preserve the original URL in the address bar. It does not change from /foo/bar to /Error/404.

With UseStatusCodePagesWithReExecute middleware, it's also possible to get the original path in the using IStatusCodeReExecuteFeature interface as shown below.

public class ErrorController : Controller
{
    [Route("Error/{statusCode}")]
    public IActionResult HttpStatusCodeHandler(int statusCode)
    {
        var statusCodeResult =
                HttpContext.Features.Get<IStatusCodeReExecuteFeature>();

        switch (statusCode)
        {
            case 404:
                ViewBag.ErrorMessage =
                        "Sorry, the resource not found";
                ViewBag.Path = statusCodeResult.OriginalPath;
                ViewBag.QS = statusCodeResult.OriginalQueryString;
                break;
        }

        return View("PageNotFound");
    }
}





Comments