Gracefully Responding to Unhandled Exceptions - Displaying User-Friendly Error PagesBy Scott Mitchell
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.configfile - 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
modeproperty, 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
defaultRedirectproperty 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
Let's look at an example. The following
<customErrors> settings displays the user-friendly error page
to all visitors in the face of an unhandled exception:
remoteOnly, we could configure it so that only remove visitors saw
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
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
Redirecting Users to Different Pages Depending on the Error
If you specify a user-friendly error page via the
defaultRedirectproperty, 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
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
For example, the following
<customErrors> settings will send the user to
they request a page that is not present, and to
GeneralServerError.aspx for any other type of unhandled exception:
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
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
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
<customErrors> settings. To display the same error page as specified in the
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|
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!
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
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