<%@ Page %>
ASP.NET Global Exception Handling
The Problem
When a runtime error occurs in ASP.NET an exception is thrown. Exceptions offer a myriad of benefits over the classic ASP error-handling model, including object-based errors, the ability to catch errors by type, and the ease of implementing structured error handling. But there are instances in every application when exceptions are not caught, and the result is a dreaded sight for developers: the default ASP.NET error page.
Click on the image to enlarge
So this begs the question: How can you ensure that users see your custom error page instead of the default page shown above?
The Solution
You can accomplish this using a few well-placed lines of code in the Global.asax. If you're unfamiliar with the Global.asax, it contains subroutines that handle application-level and session events such as the start of the application (Application_Start), the start of user sessions (Session_Start), and several others. The handler of interest in this article is the Application_Error subroutine that runs when an exception makes its way past your application code.
The process for handling these exceptions is as follows:
- Create an ASP.NET page called error.aspx; this is your custom error page. We'll examine the code for it in a moment.
- In the Global.asax code-behind catch the last exception thrown.
- Pull out the InnerException from the exception caught above. This is necessary because when an unhandled exception occurs .NET wraps it in a new exception of type HttpUnhandledException.
- Place a few key values in the Session for retrieval on the custom error page.
- Clear the error from the server.
- Redirect to the custom error page.
The Global.asax.vb code
The following listing shows the code necessary to achieve this:
Sub Application_Error
(ByVal sender As Object, ByVal e As EventArgs)
Try
' set default values
Session("ErrorMsg") =
"No error information was available"
Session("ExceptionType") = String.Empty
Session("PageErrorOccured") = _
Request.CurrentExecutionFilePath
Session("StackTrace") = String.Empty
' 2. Catch the last exception thrown
Dim lastError As Exception = Server.GetLastError()
' 3. Pull out the InnerException
If (Not lastError Is Nothing) Then
lastError = lastError.InnerException
' 4. Place a few key values in the session for
' retrieval on the custom error page
Session("ErrorMsg") = lastError.Message
Session("ExceptionType") = lastError.GetType.ToString
Session("StackTrace") = lastError.StackTrace
End If
' 5. Clear the error from the server
Server.ClearError()
' 6. Redirect to the custom error page
Response.Redirect("error.aspx")
Catch ex As Exception
' if we end up here,
'error handling has thrown an error.
' do nothing - don't want to create an infinite loop
Response.Write("We apologize, but an" & _
" unrecoverable error has occurred. Please click the " & _
" back button on your browser and try again.")
End Try
End Sub
Your Custom Error Page
The process to follow in your error page code-behind is:
- Add an ASP.NET label and name it lblMessage.
- Grab the exception information placed in the session in Global.asax.vb.
- Clear the values from the session.
- Display a generic error message to the user. We will even include a link back to the offending page.
- Add specific error information as HTML comments for use during development. This code should be removed when the application is moved to the production.
In the error.aspx.vb Page_Load, place the following:
Try
If (Not IsPostBack) Then
' 2. Grab the exception information from the session
Dim errorMsg As String =
CStr(Session("ErrorMsg"))
Dim pageErrorOccured As String =
CStr(Session("PageErrorOccured"))
Dim exceptionType As String =
CStr(Session("ExceptionType"))
Dim stackTrace As String =
CStr(Session("StackTrace"))
' 3. Clear the values from the session
Session("ErrorMsg") = Nothing
Session("PageErrorOccured") = Nothing
Session("ExceptionType") = Nothing
Session("StackTrace") = Nothing
' 4. Display a generic error message to the user
lblMessage.Text = "We're sorry, but an unhandled " & _
"error has occurred.<br/><br/>"
lblMessage.Text =
String.Format("{0}To try again, " & _
"click <a href='{1}' class='linkgreen'>
here</a>.<br/><br/>", _
lblMessage.Text, pageErrorOccured)
' 5. Add specific error information as
'HTML comments for you
' to view during development.
'You could also log the error to
' the Windows event log here.
lblMessage.Text = lblMessage.Text & "<!--" & Chr(10) & _
"Error Message: " & errorMsg & Chr(10) & _
"Page Error Occurred: " & pageErrorOccured & Chr(10) & _
"ExceptionType: " & exceptionType & Chr(10) & _
"Stack Trace: " & stackTrace & Chr(10) & _
"-->"
End If
Catch ex As Exception
' If an exception is thrown in the
' above code output the message
' and stack trace to the screen
lblMessage.Text = ex.Message & " " & ex.StackTrace
End Try
To test this code create a new web form called ThrowsAnException.aspx and modify the Page_Load as follows:
Private Sub Page_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs)
Handles MyBase.Load
Throw New Exception("Something didn't work right.")
End Sub
Upon running ThrowsAnException.aspx you will see your custom error page with the generic message and the link back to the offending page. If you view the HTML source in your browser you will see your error message ("Something didn't work right") and a stack trace in the HTML comments.
Conclusion
It always reflects poorly on a developer's code when users encounter errors, but additional damage is done when they are faced with an indecipherable error message on a nasty error page. The techniques discussed in this article allow you to show the user an attractive error page no matter what type of error has occurred.
Rob Walling is a Microsoft Certified Professional in VB.NET Web Applications and has worked as a software developer for the past four years. His areas of expertise include ASP.NET, VB.NET, and web-based application design. Rob is the principal of the Los Angeles-based consulting firm The Numa Group.