Back to: ASP.NET Core Tutorials For Beginners and Professionals
Handling Non-Success HTTP Status Codes in ASP.NET Core MVC
In this article, I will discuss Handling Non-Success HTTP Status Codes, i.e., the use of UseStatusCodePages, UseStatusCodePagesWithRedirects, and UseStatusCodePagesWithReExecute middleware components in ASP.NET Core MVC Application with Examples. Please read our previous article discussing Exception Filter in ASP.NET Core MVC Applications.
Here, we will discuss how to handle 404 Errors, i.e., Page Not Found Errors, in a centralized way with different approaches. At the end of this article, you will understand the following 3 Middleware Components that deal with Status Code Pages in ASP.NET Core MVC Applications.
- UseStatusCodePages
- UseStatusCodePagesWithRedirects
- UseStatusCodePagesWithReExecute
Types of 404 Errors in ASP.NET Core MVC
There are 2 types of 404 errors.
Type 1: Resource With the Specified ID Does Not Exist.
This type of 404 error occurs when we cannot find the employee, product, customer, etc., with the provided ID. Let us understand this with an example. First, create the following Product model, which will display the Product details to the user.
namespace FiltersDemo.Models { public class Product { public int Id { get; set; } public string Name { get; set; } public decimal Price { get; set; } } }
Modifying the Controller:
Then modify the HomeController as follows. Please have a look at the Details action method. Here, if the Product details are found, it will render the Details view with the Product details. On the other hand, if the Product is not found, it renders the ProductNotFound view.
using FiltersDemo.Models; using Microsoft.AspNetCore.Mvc; namespace FiltersDemo.Controllers { public class HomeController : Controller { public ActionResult Index() { return View(); } public ViewResult Details(int id) { //Let us assume the Product with the given Id is does not exists in the database Product? product = null; if (product == null) { Response.StatusCode = 404; return View("ProductNotFound", id); } return View(product); } } }
Creating ProductNotFound View:
Next, create a view with the name ProductNotFound.cshtml within the Views/Home folder and copy and paste the following code. In this case, we know the user is trying to go to the Product details page, but the provided Product ID value is invalid. So, we are returning a custom error page with the message; the ID Does Not Exist.
@model int @{ ViewBag.Title = "404 Error"; } <div class="alert alert-danger mt-1 mb-1"> <h4>404 Not Found Error :</h4> <hr /> <h5> Product with ID = @Model Does Not Exists </h5> </div>
Now, access the Home/Details/10 URL, and you will see the following error message.
Type 2: The Provided URL Does Not Match Any Route In Your Application.
Consider the following URL, which does not exist. This also results in a 404 error.
In this case, we are unaware of the page the user is trying to get, so displaying a custom error page is impossible. Now, let us proceed and understand how to handle this type of 404 error centrally.
Default 404 Error Page in ASP.NET Core
We have nothing configured in the HTTP request processing pipeline to handle 404 errors. So, if we navigate to /Home/Something, we see the following default 404 error page. This is because the URL /Home/Something does not match any routes in our application.
Handling Non-Success HTTP Status Codes in ASP.NET Core MVC:
To handle non-success HTTP status codes such as 404 in ASP.NET Core MVC Application, we can use the following 3 built-in Middleware components.
- UseStatusCodePages
- UseStatusCodePagesWithRedirects
- UseStatusCodePagesWithReExecute
UseStatusCodePages Middleware in ASP.NET Core MVC
This is the least useful middleware component among the 3. It always gives a Generic Error Message, and we don’t have the option to customize or provide a user-friendly message. For this reason, we rarely use it in a real-time application.
To use it in our ASP.NET Core MVC Application and see what it can do, we need to register it into the Request Processing pipeline. So, modify the Program class as follows to register the UseStatusCodePages Middleware Components, and this component will come into existence when the environment is not Development:
namespace FiltersDemo { public class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllersWithViews(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseStatusCodePages(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.Run(); } } }
With UseStatusCodePages Middleware configured, now, if we navigate to URL /Home/Something, it returns the following simple text response.
UseStatusCodePagesWithRedirects Middleware in ASP.NET Core MVC
We want to handle these non-success HTTP status codes (other than 200 Status Code) in the production environment and return a Custom Error Page. To achieve this, we can either use UseStatusCodePagesWithRedirects or UseStatusCodePagesWithReExecute middleware components. Let’s understand these two Middleware Components with Examples, and then we will see the differences.
First, create the Error Controller and copy and paste the following code. Here, within the HttpStatusCodeHandler action method, we check if the status code is 404. If it is 404, we set the custom error message into the ErrorMessage ViewBag property and render the NotFound view.
using Microsoft.AspNetCore.Mvc; namespace FiltersDemo.Controllers { 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"); } } }
Creating NotFound View:
Next, we need to add the NotFound.cshtml view within the Views/Error folder. Once you add the view, copy and paste the following code. Here, we are simply displaying the ViewBag.ErrorMessage property value, which is set by the HttpStatusCodeHandler action method.
@{ ViewBag.Title = "Not Found"; Layout = null; //If you want the Layout, you can set the layout } <h1>@ViewBag.ErrorMessage</h1>
Next, modify the Program class as follows. Here, you can see we are registering the UseStatusCodePagesWithRedirects middleware component, which will come into existence when the environment is not set to Development.
namespace FiltersDemo { public class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllersWithViews(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseStatusCodePagesWithRedirects("/Error/{0}"); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.Run(); } } }
The following line of code is in place: If there is a 404 error, the user is redirected to /Error/404. The placeholder {0}, in “/Error/{0}” will automatically receive the HTTP status code.
app.UseStatusCodePagesWithRedirects(“/Error/{0}”);
Run the application and navigate to the URL /Home/Something. You will see the following custom 404 error view NotFound.cshtml as expected.
To use UseStatusCodePagesWithReExecute middleware instead of UseStatusCodePagesWithRedirects middleware
REPLACE app.UseStatusCodePagesWithRedirects(“/Error/{0}”);
WITH app.UseStatusCodePagesWithReExecute(“/Error/{0}”);
Re-run the application and navigate to /Home/Something, and you should see the same custom 404 error view NotFound.cshtml. The obvious question that should come to your mind is, what’s the difference between these 2 middleware components, and which one we should use?
Difference Between UseStatusCodePagesWithRedirects and UseStatusCodePagesWithReExecute Middleware in ASP.NET Core MVC:
In an ASP.NET Core MVC Application, UseStatusCodePagesWithRedirects and UseStatusCodePagesWithReExecute are middleware components that handle NON-SUCCESS HTTP Status Codes and provide custom error handling. Before understanding the differences between these two Middleware Components, we first need to understand how they handle the no-success HTTP Status code internally.
Request Processing with UseStatusCodePagesWithRedirects in ASP.NET Core MVC
So, when the UseStatusCodePagesWithRedirects handles the Non-Success HTTP Status Code, it will actually return a 302 Status code to the browser. When it returns the 302 Status Code, it also provides the GET Request Path to be executed by the browser, and the browser will issue a new Request to the requested path. The GET Request path needs to be configured in the UseStatusCodePagesWithRedirects component. In this case, the /Error/{0}, i.e., /Error/404 as the placeholder {0}, will be replaced by the Status Code 404.
302 status code means the URI of the requested resource has been temporarily changed; in our case, it changed from /Home/Something to /Error/404. Hence, the browser will issue another GET Request with the updated URL, /Error/404. Because a redirect is issued, the URL in the address bar changes from /Home/Something to /Error/404.
The new GET request (i.e., /Error/404) flows through the pipeline. It is handled by the HttpStatusCodeHandler action method of Error Controller, which will return the NotFound view HTML with status code 200 (which means the request was completed successfully). As far as the browser is concerned, in this entire request flow, there was no 404 error. For a better understanding, please have a look at the following diagram:
Request Processing with UseStatusCodePagesWithReExecute in ASP.NET Core MVC
The UseStatusCodePagesWithReExecute middleware also intercepts responses with error status codes. Instead of redirecting the client to a new URL, it re-executes the request pipeline using an internal rewrite to the specified path.
In our example, when a request is issued to /Home/Something, a 404 status code is raised. The UseStatusCodePagesWithReExecute middleware intercepts the 404-status code and re-executes the pipeline, pointing it to the URL (/Error/404). The request then flows through the pipeline and is handled by the MVC middleware (HttpStatusCodeHandler action method of Error Controller handles the request), which returns NotFound view HTML with status code 200. Then, the UseStatusCodePagesWithReExecute middleware uses the HTML response returned by the NotFound view but replaces the 200 status code with the original 404 status code.
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, it preserves the original URL (/Home/Something) in the address bar. It does not change from /Home/Something to /Error/404. For a better understanding, please have a look at the following diagram:
Key Differences:
The following is the key difference between UseStatusCodePagesWithRedirects and UseStatusCodePagesWithReExecute:
- UseStatusCodePagesWithRedirects redirects the browser to a different URL for error handling, resulting in a new request to the error page. So, use UseStatusCodePagesWithRedirects when you need a simple way to redirect the users to an error page without much concern about the original URL or request method.
- UseStatusCodePagesWithReExecute re-executes the original request with a modified route to handle errors within the same request pipeline. So, use UseStatusCodePagesWithReExecute when maintaining the original URL is important, and you might need to handle errors differently based on the original context of the request.
In the next article, I will discuss Error Pages Based on Status Codes in ASP.NET Core MVC Applications. In this article, I try to explain Error Pages Based on Status Codes in ASP.NET Core MVC Applications with Examples. I hope you enjoy this Error Pages Based on Status Code in the ASP.NET Core MVC article.