asp:feature companion
LANGUAGES: VB .NET
TECHNOLOGIES: Exception Handling
Customize Default ASP.NET Exception Handling
ASP.NET has a default exception-handling system, but it ain't pretty - unless you take the time to customize it.
By Don Kiely
Like pretty much every development environment in the history of computing, ASP.NET has a default exception handling system, which is unlikely to be acceptable for any production application. Suppose you have this code in a Page's Load event procedure:
Dim x As Integer = 44
Dim y As Integer = 31
Dim z As Double
Dim zi As Double
z = x / y
zi = x \ y
lblResult.Text = "When x is " & x.ToString _
& " and y is " & y.ToString _
& ", x / y is " & z.ToString _
& ", and x \ y is " & zi.ToString & "."
Now suppose somehow the variable y in the previous code is 0 instead of 31. Interestingly, the result of the floating-point division assigned to z is a special value of infinity, so the line z = x / y doesn't throw an error. But the line zi = x / y does throw an exception, which is not handled in this procedure or anywhere else in the application. So the ASP.NET default behavior kicks in.
What the user sees depends on where the application is running. If the browser is running on the same machine as the application, which is a common scenario during development, the user sees Figure 1. In many cases, this provides enough information to find what went wrong so you can fix the problem.
Figure 1. With the default
configuration out of the box, a user running an application with an unhandled
exception gets a fair bit of information about what caused the problem,
including a stack trace.
If the browser is running on a remote machine, such as when an application goes into testing or production and real users are hitting the server, the same error will present the user with Figure 2.
Figure 2. Still using the default
ASP.NET configuration, a remote user will get this less-than-useful page.
Unless you hate your users, decide right now that no one will ever see this in
an application of yours.
I don't know about you, but I'll work awfully hard to keep my users from seeing a message that seems to imply that whatever idiot set up this application didn't configure it right. That's not the message I want to convey, no matter how wrong (or right) it might be!
This default behavior is affected by the customErrors
element in web.config. The default behavior is equivalent to this line in the
This tells ASP.NET that when an unhandled exception
occurs, it should present remote users with the "bad configuration" page, and
local users should get the detailed debugging information. Because this is the
default, the lack of a
The mode attribute has two other settings: On and Off. On simply means all users get the somewhat useless "bad configuration" page; Off means all users get the detailed debugging page. (In the sample application, set Default.aspx as the start page and see the instructions there for modifying web.config to explore these behaviors.)
You can customize this default behavior further by using
the defaultRedirect attribute of
mode="On" /> Now when an unhandled exception occurs, the user is
presented with whatever content you provide in the static GenericError.htm
page, such as the one I've set up in Figure 3. Note that the mode attribute
affects behavior in the same way described above, so On means every user sees
GenericError.htm, Off means no one does, and RemoteOnly means only remote users
see it while local users get debugging information. This is a bit better because it presents the user with
something consistent with the visual design of the application. You can control
what the page says, and everyone feels better (hopefully). Notice in the address bar in Figure 3 that ASP.NET
includes a querystring parameter, aspxerrorpath, which includes the path of the
offending aspx page. If you want, you could incorporate this in the error page
using an aspx page instead of static HTML: This results in the error page
shown in Figure 4, which includes a new middle paragraph. This simple example uses inline code to display the query
string information. You can, of course, write whatever complex code you need to
present whatever makes sense in a particular application: <% If Not Request.QueryString("aspxerrorpath") Is
Nothing %> In case you didn't
know, the error arose from <%=HttpUtility.HtmlEncode(Request.QueryString("aspxerrorpath"))%> .
Figure 3. By redirecting users to a
custom error page, you can soften the blow a bit when something goes wrong.
Figure 4. Because ASP.NET includes
the aspxerrorpath querystring attribute, you can include information about which
page caused the error.
<% End If %>
Another configuration option with
In the
One thing to be careful of here is that HTTP status code 500 acts as a sort of catch-all for most run-time code errors. So in the sample application, the divide-by-zero error is redirected to Error500.htm rather than GenericError.aspx.
With this technique, you also can define custom errors in IIS and hook into them with custom error pages. You aren't limited to the predefined HTTP errors.
Don Kiely is senior information architect for Information Insights, a business and technology consultancy in Fairbanks, Alaska. E-mail him at mailto:[email protected].