Error handling in ASP.NET 5

By Piotr on (tags: ASP.NET5, error, mvc6, web, categories: web)

There is a lot of changes since MVC5 regarding error handling. I will show you how to catch and handle some basic errors. Here is a nice article by Krzysztof about error handling in MVC5.

First of all let me explain what “middleware” is…. or even better – here is the definition of middleware provided by OWIN from here:

Pass through components that form a pipeline between a server and application to inspect, route, or modify request and response messages for a specific purpose.

Middleware is our component which we can plug in to request pipeline. We will use it to handle errors.

500 – internal server error

This is the simple one, we can just use builtin middleware “UseErrorHandler”. Modify Startup.cs as below:

   1: public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
   2:         {
   3: //…
   4:                     app.UseErrorHandler("/Home/Error");

As you can there is nice way to handle basic exception and invoke our controller. In this case Home controller and Error action.

Our Error action will look like:

   1: public IActionResult Error()
   2: {
   3:     var error = Context.GetFeature<IErrorHandlerFeature>();
   4:     return View("~/Views/Shared/Error.cshtml");
   5: }

Look at line “var error = Context.GetFeature<IErrorHandlerFeature>();”. The IErrorHandlerFeature interface has only one property: Exception – isn’t that just nice? Now we have exception context in our controller.

400 – bad request

This type of error requires from us to use different middleware – which is also builtin: “UseStatusCodePagesWithReExecute”.

Startup.cs:

   1: public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
   2: {
   3: //…
   4: app.UseStatusCodePagesWithReExecute("/Errors/Error{0}");

What is happening here? Middleware will re-execute all request, which response has some HTTP error code and has empty body - to our controller. The “{0}” is placeholder for HTTP status code, so in this example, every response which has 400 code will be automatically redirected to http://localhost/Errors/Error400.

This is very basic scenario. If we want to do some more complex stuff we will need to write a custom middleware

404 – not found

This is specific error. First of all we need to catch it before IIS will. All not-handled requests will be handled by IIS by default (which is normal). That means that we need to handle all requests regardless if the route exists or not. Below I wrote simple RequestDelegate and I attached it as a last in pipeline. If our request won’t be handled by any of our routes then we know that the resource doesn’t exist:

   1: app.UseMvc(routes =>
   2: {
   3: routes.MapRoute(
   4: name: "default",
   5: template: "{controller=Home}/{action=Index}/{id?}");
   6: });
   7: // Handle every request
   8: app.Run(context =>
   9: {
  10: context.Response.StatusCode = 404;
  11: return Task.FromResult(0);
  12: });

That simple code will do two things – prevent request to be handled by IIS and will set status of response to 404. Thanks to our previous way of handle errors (app.UseStatusCodePagesWithReExecute("/Errors/Error{0}");) the request will be redirect to http://localhost/Errors/Error404.

Conclusion

Now you know how to handle basic error types. If you need to handle some advanced scenario then you will need to write you own middleware, which is rather simple task. That mechanism gives us a lot of controll and I belive is very simple to uderstand.