To read the article online, visit http://www.4GuysFromRolla.com/articles/090606-1.aspx

Gracefully Responding to Unhandled Exceptions - Displaying User-Friendly Error Pages

By Scott Mitchell


The default page displayed to remote visitors when an unhandled exception occurs.

Introduction


In .NET applications, an illegal operation - an invalid cast, attempting to reference a null value, trying to connect to a database that's been taken offline, and so on - raises an exception. Exceptions can be caught and handled directly in code through the use of Try / Catch blocks. For ASP.NET applications, if the exception is not handled in code, it bubbles up to the ASP.NET runtime, which raises an HttpUnhandledException. By default, unhandled exceptions result in a page that displays the text, "Runtime Error" with instructions for developers on how to display exception details (see the screen shot to the right). This "Runtime Error" error page is what is seen by external visitors; if you visit your site through localhost and an unhandled exception occurs, the default error page includes the type and details of the exception thrown. [View a screenshot]

End users will no doubt find the "Runtime Error" page to be intimidating and confusing - do you think the average computer user knows what "Runtime" means? All the user knows is that something went horribly wrong. They might fear that their data or progress has been lost and that they are responsible for the error. Ironically, the person who does care that an unhandled exception has occurred - the developer - is left out of the loop unless the end user takes the time to email the developer the details of the error (what page it happened on, the steps the user had performed that caused the error, and so on).

Fortunately, ASP.NET provides solutions to these two problems. An ASP.NET application can be configured to automatically redirect the user to a less-intimidating page that explains that there has been a problem. This custom, user-friendly error page can omit such lingo like "Runtime" and have its look and feel match the website's. Additionally, there are techniques available to log and alert the developer of the unhandled exception. In this article we'll look at how to display user-friendly error pages in the event of an unhandled exception. A future article (Processing Unhandled Exceptions) will examine how to log and alert the site administrator when such exceptions occur. Read on to learn more!

Displaying a User-Friendly Error Page in the Face of an Unhandled Exception


When an unhandled exception bubbles up to the ASP.NET runtime, the application's <customErrors> settings are consulted. These settings - specified in the application's Web.config file - determine whether a visitor sees the "Runtime Error" page, a page with details about the exception, or some custom, user-friendly error page. What action is taken depends upon the <customErrors> setting's mode property, which can have one of the following three values:
  • On - the "Runtime Error" page or custom, user-friendly error page is shown to all visitors in the face of an unhandled exception
  • Off - the exception details page is shown to all visitors in the face of an unhandled exception
  • remoteOnly - remote users - those not coming through localhost - see the "Runtime Error" page or custom, user-friendly error page; local visitors - the developers, typically - see the exception details page
To display a user-friendly error page instead of the default "Runtime Error" page, set the <customErrors> setting's defaultRedirect property to the URL of the user-friendly error page. The user-friendly error page can be a static HTML page or an ASP.NET page; it can be an absolute URL (like http://www.someserver.com/SomePage.htm) or relative to your website. Relative URLs can use ~ to base the file path at the root of the web application (such as ~/ErrorPage.aspx).

Let's look at an example. The following <customErrors> settings displays the user-friendly error page GeneralServerError.aspx to all visitors in the face of an unhandled exception:

<customErrors mode="On" defaultRedirect="~/GeneralServerError.aspx" />

By changing mode to remoteOnly, we could configure it so that only remove visitors saw GeneralServerError.aspx in the face of an exception. Those coming through localhost would see details of the exception.

When an unhandled exception bubbles up to the ASP.NET runtime, the runtime notes the <customErrors> settings and internally issues a Response.Redirect() to the defaultRedirect. This sends a 302 HTTP status code down to the browser, which instructs it to request the specified URL (GeneralServerError.aspx, in this example). The runtime also appends to the specified URL a querystring parameter named aspxerrorpath, which refers to the URL the user was visiting when the unhandled exception was raised. The user-friendly error page - GeneralServerError.aspx - can display some message to the user explaining that there's a problem.

The download available at the end of this article includes a sample ASP.NET 2.0 web application that illustrates using the <customErrors> settings...

Redirecting Users to Different Pages Depending on the Error


If you specify a user-friendly error page via the <customErrors> settings defaultRedirect property, a user will be directed to that web page when any unhandled exception bubbles up to the runtime. This includes both internal server exceptions - which have a status code of 500 - and HTTP-related exceptions, such as 404 page not found exceptions. The <customErrors> settings can be customized to direct the user to a different web page depending on the HTTP status code of the exception. That is, you can have one page displayed in the face of a 404 error, and another in the face of an internal server exception.

To customize the <customErrors> settings, add an <error> element detailing the page to send users to when an exception from a specific HTTP status code is raised. You may include zero to many <error> elements. If the status code of the raised exception is not found in the list of <error> elements, the user will be sent to the page specified by the defaultRedirect property.

For example, the following <customErrors> settings will send the user to FourOhFour.aspx if they request a page that is not present, and to GeneralServerError.aspx for any other type of unhandled exception:

<customErrors mode="On" defaultRedirect="~/GeneralServerError.aspx">
   <error statusCode="404" redirect="~/FourOhFour.aspx" />
</customErrors>

Such a 404 page can determine the non-existent page that was requested through the aspxerrorpath querystring field. In other words, if a user attempts to visit a non-existent page - www.server.com/NoSuchPage.aspx - the ASP.NET runtime will redirect the user to www.server.com/FourOhFour.aspx?aspxerrorpath=/NoSuchPage.aspx. Additionally, we can determine whether the user requested the non-existent web page by clicking on a link from some other page. In such a case, the initial page has a broken link that needs to be fixed! You can determine if the user reached the non-existent page from another page by consulting the Request.UrlReferrer property in ASP.NET 2.0 or the Request.ServerVariables("HTTP_REFERER") variable in ASP.NET 1.x.

Keep in mind that the <customErrors> settings can only be applied by the ASP.NET runtime when an unhandled exception occurs when requesting an ASP.NET resource. For example, when using IIS as your web server, requests to static resources, such as HTML pages, are handled by IIS and are not handed off to the ASP.NET engine. Therefore, if the user attempts to visit a non-existent HTML page, IIS will respond with a 404 status code instead of redirecting the request to the page dictated by the <customErrors> settings. To display the same error page as specified in the <customErrors> settings, you can create a custom 404 page in IIS or map HTML pages to the ASP.NET engine.

Note that the ASP.NET Development Web Server that ships with Visual Studio 2005 and is used for file system-based websites maps all resources to the ASP.NET engine. Therefore, the <customErrors> settings will be used when requesting an HTML page...

Improving the 404 Error Page
The FourOhFour.aspx error page succeeds in displaying a user-friendly message to the end user informing them that they've attempted to visit a non-existent page. With a bit of code we can greatly extend to utility of the 404 error page. For example, if a user reaches a non-existent web page through a broken link on some other page, it would be nice to shoot an email to the developers so that they can fix the broken link. For information on how to send an email from an ASP.NET web page, see Sending Email in ASP.NET 2.0 or Sending Email from an ASP.NET 1.x Web Page.

Another possible enhancement would be to build a database table that includes mappings from invalid URLs to valid ones. In the 404 error page, a database lookup would be performed to determine if the non-existent page requested has a "valid" URL in the table. If so, the user would be automatically redirected to the valid URL. Such functionality would be a handy way to deal with the following situation: imagine another website has a link to a particular page on your website, but the link has a typo making it a broken link. Ideally, the link on the other website would be fixed, but rather than wait for someone else to fix the problem, you could proactively map the mistyped URL to the intended page. Then, when a user came to your site through the other website's broken link, they'd automatically be redirected to the correct page!

Conclusion


In the face of an unhandled exception, the ASP.NET runtime can take one of three actions: show the generic "Runtime Error" page; display the exception's details; or display a custom, user-friendly error page. By default, remote visitors are shown the "Runtime Error" page and those visiting through localhost - developers, typically - see the exception details page. However, the default "Runtime Error" page can easily be replaced with a custom error page. These settings can be customized through the <customErrors> element in Web.config.

One issue with custom, user-friendly error pages specified through the <customErrors> settings is that they cannot obtain details about the exception that just occurred other than the page on which the exception occurred (through the aspxerrorpath querystring field). Ideally, the custom error page would be able to log the exception's details or perhaps customize the message displayed to the end user based on the exception. Workarounds to these shortcomings are discussed in Processing Unhandled Exceptions, along with a discussion of a free, open-source library that can automatically log and notify developers about unhandled exceptions!

Happy Programming!

  • By Scott Mitchell


    Further Readings:


  • Processing Unhandled Exceptions
  • Attachments


  • Download example code for this article (in ZIP format)
  • Article Information
    Article Title: ASP.NET.Gracefully Responding to Unhandled Exceptions - Displaying User-Friendly Error Pages
    Article Author: Scott Mitchell
    Published Date: September 6, 2006
    Article URL: http://www.4GuysFromRolla.com/articles/090606-1.aspx


    Copyright 2014 QuinStreet Inc. All Rights Reserved.
    Legal Notices, Licensing, Permissions, Privacy Policy.
    Advertise | Newsletters | E-mail Offers