Online courses in ASP.NET MVC, ASP.NET Core, and Design Patterns conducted by Bipin Joshi. Read more...
Learn ASP.NET MVC, ASP.NET Core, and Design Patterns through our online training programs. Courses conducted by Bipin Joshi on weekends. Read more details here.

Five Methods to Deal with Errors in ASP.NET Core

Error handling is a common practice in any real-world web application. In ASP.NET Web Forms you used certain events and custom error pages to deal with them. In ASP.NET MVC you used [HandleError] attribute, exception filters and custom error pages to deal with them. In ASP.NET Core you have a set of methods and, of course, exception filters at your disposal. In this article I will discuss five methods that are used in connection with error handling.

These methods are called from the Configure() method of the startup class. They are available as extension methods of the IApplicationBuilder object received by the Configure() method. These extension method basically call the Microsoft.AspNetCore.Diagnostics middleware to get their job done.

To see these methods in action, create a new ASP.NET Core application based on Web Application project template. Then open the HomeController and deliberately throw an exception from the Index() action as shown below:

public IActionResult Index()
{
    throw new Exception("This is some exception!!!");
    return View();
}

The code shown above is quite straightforward and needs no explanation.

Now let's discuss the five methods one by one.

1. UseDeveloperExceptionPage() - Inspect exception details during development

The  UseDeveloperExceptionPage() method is handy during development stage. To use this method open the Startup.cs file, locate the Configure() method and change it to look like this:

public void Configure(IApplicationBuilder app, 
IHostingEnvironment env, 
ILoggerFactory loggerFactory)
{
  app.UseDeveloperExceptionPage();
  ....
  ....
}

As you can see UseDeveloperExceptionPage() method has been called on the app object. If you run the application you will see this in the browser:

As you can see the detailed error repost has been rendered in the browser. The Stack, Query, Cookies and Headers sections display the respective information.

As mentioned earlier this method should be called only during development stage because you don't want to show the exception details to the end user. That's why it is always good idea to call UseDeveloperExceptionPage() method like this:

if (env.IsDevelopment())
{
  app.UseDeveloperExceptionPage();
}
else
{
  //something else here
}

Now the UseDeveloperExceptionPage() is housed inside an if block. If the hosting environment is development IsDevelopment() method returns true and only then UseDeveloperExceptionPage() gets called. Otherwise some other error handling code gets executed.

2. UseExceptionHandler() - Handover the control to a custom error handler

The UseExceptionHandler() method uses a specified error handler to deal with the exception. The error handler might log the exceptions and show a friendly message to the end user. To use this method first of all open the HomeController and locate the Error() action. This action is added as a part of the Web Application project template and also has the corresponding view - Error.cshtml - inside the Views folder.

Modify the Error() action as shown below:

public IActionResult Error()
{
    var exception = HttpContext.Features
    .Get<IExceptionHandlerFeature>();

    ViewData["statusCode"] = HttpContext.
                    Response.StatusCode;
    ViewData["message"] = exception.Error.Message;
    ViewData["stackTrace"] = exception.
                   Error.StackTrace; 

    return View();
}

The Error() action extracts exception details and sends them to the Error view through ViewData. To grab the exception that was thrown the code uses Features.Get() method on HttpContext. The HTTP status code is obtained using the Response.StatusCode property. The status code, exception message and exception stack trace are stored in ViewData dictionary for the use on the Error view.

Now open Error view and modify it as shown below:

<h1>@ViewData["message"]</h1>

<h2>Status Code : @ViewData["statusCode"]</h2>

<div>@ViewData["stackTrace"]</div>

The above code is quite straightforward and needs no explanation.

Finally, go to the Configure() method again and modify it to call UseExceptionHandler().

public void Configure(IApplicationBuilder app, 
IHostingEnvironment env, 
ILoggerFactory loggerFactory)
{
  app.UseExceptionHandler("/Home/Error");
  ....
  ....
  ....
  ....
}

As you can see, this time we call UseExceptionHandler() method and specify /Home/Error action as a string parameter. This way whenever there is any unhandled exception control will be taken to Error() action.

If you run the application you will get the exception details like this:

3. UseStatusCodePages() - Show error pages for HTTP status codes

The two techniques discussed so far deal with the unhandled exceptions arising from your code. However, that's not the only source of errors. Many a times errors are generated due to internal server errors, non existent pages, web server authorization issues and so on. These errors are reflected by the HTTP status codes such as 500, 404 and 401.

To deal with such errors you can use UseStatusCodePages() method. This method can be used as follows:

public void Configure(IApplicationBuilder app, 
IHostingEnvironment env, 
ILoggerFactory loggerFactory)
{
  ....
  ....
  app.UseStatusCodePages();
  ....
  ....
}

Simple. Run the application and try to navigate to some page that doesn't exist. You will see the following:

 

Although the default rendering allows us to see the HTTP status code, it is plain text. It would be great if you format it as an HTML fragment. You can do that as shown below:

app.UseStatusCodePages("text/html", 
"<h1>Status code page</h1> <h2>Status Code: {0}</h2>");

The UseStatusCodePages() method now uses HTML markup to render the status code. Notice the use of {0} to output the status code at a specific place within the markup.

This time your error page will look like this :

4. UseStatusCodePagesWithRedirects() - Perform URL redirection upon error

At times you may want to handover the control to some action whenever there is some HTTP error (such as 404). That's where UseStatusCodePagesWithRedirects() comes handy. It sends HTTP status code 302 (Found) to the browser and performs the redirection using the action specified. Consider the following code:

public void Configure(IApplicationBuilder app, 
IHostingEnvironment env, 
ILoggerFactory loggerFactory)
{
  ....
  ....
  app.UseStatusCodePagesWithRedirects("/CustomErrorPages/{0}");
  ....
  ....
}

The code calls UseStatusCodePagesWithRedirects() method and passes /CustomErrorPages/{0} as a string parameter. The {0} placeholder is used only if you wish to pass the status code (such as 404) to the handler. Then add another action to the HomeController as shown below :

[Route("/CustomErrorPages/{code}")]
public IActionResult StatusCodeErrors(string code)
{
ViewData["statusCode"] = code;
return View();
}

The [Route] attribute maps /CustomErrorPages to StatusCodeErrors(). The StatusCodeErrors() action accepts code parameter that is the HTTP status code. Make sure to add the StatusCodeErrors view and output the ViewData statusCode value on it.

If you attempt to access a non-existing page this time your browser will look like this:

Note that this response is rendered by Error view. The {0} placeholder passed 404 to the Error() action. You can conditionally render some different view based on the status code if you so wish. You can also device a mechanism like this:

app.UseStatusCodePagesWithRedirects("/CustomErrorPages/{0}.html");

As you can see the code now redirects to separate HTML pages stored as 404.html, 500.html and so on. This way you can display different custom error pages for different status codes.

5. UseStatusCodePagesWithReExecute() - Re-execute the request pipeline with alternate action

The UseStatusCodePagesWithReExecute() is similar to UseStatusCodePagesWithRedirects() in that both execute some alternate action if there is any HTTP error. However, UseStatusCodePagesWithRedirects() does redirection to the alternate action whereas UseStatusCodePagesWithReExecute() re-executes the entire request pipeline and executes the alternate action. The UseStatusCodePagesWithRedirects() sends status code of 302 to the browser and browser address bar reflects the new URL upon redirection. In case of UseStatusCodePagesWithReExecute() the original status code is sent to the browser and the address bar will continue to show the original URL.

You can use the UseStatusCodePagesWithReExecute() method as follows :

public void Configure(IApplicationBuilder app, 
IHostingEnvironment env, 
ILoggerFactory loggerFactory)
{
  ....
  ....
  app.UseStatusCodePagesWithReExecute("/CustomErrorPages/{0}");
  ....
  ....
}

This time also the browser output is same as before but the URL doesn't change as in the earlier case.

That's it for now! Keep coding!!




Bipin Joshi is a software consultant, trainer, author and a yogi having 21+ years of experience in software development. He conducts online courses in ASP.NET MVC / Core, jQuery, AngularJS, and Design Patterns. He is a published author and has authored or co-authored books for Apress and Wrox press. Having embraced Yoga way of life he also teaches Ajapa Meditation to interested individuals. To know more about him click here.

Get connected : Twitter  Facebook  Google+  LinkedIn

Posted On : 02 Jan 2017



Tags : ASP.NET ASP.NET Core MVC C# Visual Studio