Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET MVC 6 handling errors based on HTTP status code

I want to display different error messages for each status code e.g:

  • 400 Bad Request
  • 403 Forbidden
  • 500 Internal Server Error
  • 404 Not Found
  • 401 Unauthorized

How can I achieve this in the new ASP.NET MVC 6 applications? Can I do this using the built in UseErrorHandler method?

application.UseErrorHandler("/error");

Also, I noticed that even with the above handler, entering a non-existent URL e.g. /this-page-does-not-exist, causes an ugly 404 Not Found error page from IIS. How can this also be handled?

In MVC 5 we have had to use the system.web customerrors section for ASP.NET and the system.webServer httpErrors section in the web.config file but it was difficult to work with an unwieldy, with lots of very strange behaviour. Does MVC 6 make this a lot simpler?

like image 308
Muhammad Rehan Saeed Avatar asked Jun 11 '15 16:06

Muhammad Rehan Saeed


People also ask

What are the 3 approaches to handling exceptions in a web application C#?

C# exception handling is built upon four keywords: try, catch, finally, and throw.

How does ASP.NET handle errors?

You can handle default errors at the application level either by modifying your application's configuration or by adding an Application_Error handler in the Global. asax file of your application. You can handle default errors and HTTP errors by adding a customErrors section to the Web. config file.

What is OkObjectResult?

OkObjectResult. An ObjectResult, when executed, performs content negotiation, formats the entity body, and will produce a Status200OK response if negotiation and formatting succeed. public OkObjectResult OkObjectResult() { return new OkObjectResult(new { Message="Hello World !" }); } C#


2 Answers

You could use the StatusCodePagesMiddleware for this. Following is an example:

public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
    app.UseStatusCodePagesWithReExecute("/StatusCodes/StatusCode{0}");

    app.UseMvcWithDefaultRoute();

Controller which handles the status code requests:

public class StatusCodesController : Controller
{
    public IActionResult StatusCode404()
    {
        return View(viewName: "NotFound"); // you have a view called NotFound.cshtml
    }

    ... more actions here to handle other status codes
}

Some Notes:

  • Check other extension methods like UseStatusCodePagesWithRedirects and UseStatusCodePages for other capabilities.
  • I tried having StatusCode as a query string in my example, but looks like this middleware doesn't handle query strings, but you can take a look at this code and fix this issue.
like image 152
Kiran Avatar answered Oct 20 '22 02:10

Kiran


How can I achieve this in the new ASP.NET MVC 6 applications? Can I do this using the built in UseErrorHandler method?

Quick answer: Not in an elegant fashion.

Explanation/Alternative: To start lets first look at what the UseErrorHandler method is actually doing: https://github.com/aspnet/Diagnostics/blob/6dbbe831c493e6e7259de81f83a04d1654170137/src/Microsoft.AspNet.Diagnostics/ErrorHandlerExtensions.cs#L25 which adds the following middleware: https://github.com/aspnet/Diagnostics/blob/6dbbe831c493e6e7259de81f83a04d1654170137/src/Microsoft.AspNet.Diagnostics/ErrorHandlerMiddleware.cs Note lines 29-78 (the invoke method)

The invoke method is executed whenever a request comes in (controlled by the location of your application.UseErrorHandler("...") in your Startup.cs). So the UseErrorHandler is a glorified way of adding a custom middleware: middleware = component that can act on an http request.

Now with that background, if we wanted to add our own error middleware that differentiated requests. We could do this by adding a similar middleware that's like the default ErrorHandlerMiddleware by modifying these lines: https://github.com/aspnet/Diagnostics/blob/6dbbe831c493e6e7259de81f83a04d1654170137/src/Microsoft.AspNet.Diagnostics/ErrorHandlerMiddleware.cs#L48-L51 With that approach we could control the redirect path based on the status code.

In MVC 5 we have had to use the system.web customerrors section for ASP.NET and the system.webServer httpErrors section in the web.config file but it was difficult to work with an unwieldy, with lots of very strange behaviour. Does MVC 6 make this a lot simpler?

Answer: It sure does :). Just like the above answer the fix lies in adding middleware. There's a shortcut to adding simple middleware via the IApplicationBuilder in your Startup.cs; at the end of your Configure method you can add the following:

app.Run(async (context) =>
{
    await context.Response.WriteAsync("Could not handle the request.");

    // Nothing else will run after this middleware.
});

This will work because it means that you reached the end of your http pipeline without the request being handled (since it's at the end of your Configure method in Startup.cs). If you want to add this middleware (in the quick fashion) with the option to execute middleware after you, here's how:

app.Use(async (context, next) =>
{
    await context.Response.WriteAsync("Could not handle the request.");

    // This ensures that any other middelware added after you runs.
    await next();
});

Hope this helps!

like image 3
N. Taylor Mullen Avatar answered Oct 20 '22 02:10

N. Taylor Mullen