asp tutorials, asp.net tutorials, sample code, and Microsoft news from 15Seconds
Data Access  |   Troubleshooting  |   Security  |   Performance  |   ADSI  |   Upload  |   Email  |   Control Building  |   Component Building  |   Forms  |   XML  |   Web Services  |   ASP.NET  |   .NET Features  |   .NET 2.0  |   App Development  |   App Architecture  |   IIS  |   Wireless
 
Pioneering Active Server
 Power Search








Active News
15 Seconds Weekly Newsletter
• Complete Coverage
• Site Updates
• Upcoming Features

More Free Newsletters
Reference
News
Articles
Archive
Writers
Code Samples
Components
Tools
FAQ
Feedback
Books
Links
DL Archives
Community
Messageboard
List Servers
Mailing List
WebHosts
Consultants
Tech Jobs
15 Seconds
Home
Site Map
Press
Legal
Privacy Policy
internet.commerce














internet.com
IT
Developer
Internet News
Small Business
Personal Technology
International

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers

HardwareCentral
Compare products, prices, and stores at Hardware Central!

Web Application Error Handling in ASP.NET
By Adam Tuliper
Rating: 17. out of 5
Rate this article


  • email this article to a colleague
  • suggest an article

    Introduction

    All applications should have error handling. This we all know. We can't always be notified of an unhandled error (and usually aren't) when one occurs on a client's machine. The advantage we have on the Web is that we can always be notified when an unhandled error occurs. With the advent of ASP.NET, there are some great new ways to handle errors. There are some differences in .NET in not only how to handle the error, but how the information is provided to you. For example, classic ASP uses Server.GetLastError to return an ASPError object. You can and should still use Server.GetLastError in .NET, but this now returns a type System.Exception. I must give Microsoft credit for making almost everything consistent in .NET, which is quite a welcome change.

    download source code

    The Problem

    Errors will occur in our applications. We try to trap for most errors using try-catch blocks (or the only possibility in tradional ASP 'on error resume next'); however, we usually don't cover every possible exception. What happens when an unhandled error occurs? Usually the user is brought to IIS's default error pages (usually located in c:\winnt\help\iishelp\common). The downsides are you have no idea when this occurs and the page doesn't have your site's look and feel. Errors are a development fact, but we strive to eliminate or handle them gracefully. With this in mind, we need to know:

    1. When an error occurs
    2. Where it occurred
    3. What the error is

    Having a central location such as the event log, database or some other log file to log errors is essential for debugging this problem later (I call this forensics debugging).

    IIS provides great error-handling capabilities (see my article at http://www.15seconds.com/issue/020821.htm). There are some problems with these though. Sometimes we know an error will occur, and we can't always trap for it in a nice way without overriding the site's (done in the IIS custom errors Page; see the article mentioned above) default error redirection page. For example, upon access to a resource that requires authentication, we may need to redirect to an application's login page. Also, a very common problem exists with Web hosts. If you have a hosted Web site, you usually have no control over its IIS configuration. Thus, setting up custom error pages can be next to impossible in traditional ASP. This is elimiated with ASP.NET, as you will learn as you read on.

    The Solution

    For such a list of problems, the solution is actually pretty simple. There are three places in ASP.NET to define what happens to these unhandled errors.

    1. In the web.config file's customErrors section.
    2. In the global.asax file's Application_Error sub.
    3. On the aspx or associated codebehind page in the Page_Error sub.

    The actual order of error handling events is as follows:

    1. On the Page itself, in the Page_Error sub (this is default, you can name it anything because it specificed Handles MyBase.Error)
    2. The global.asax Application_Error sub
    3. The web.config file

    Note: To cancel the bubbling up of the error at anytime for the Page_Error or Application_Error, call the "Server.ClearError" function in your sub. Each method has its own uses, as I will explain.

    When an exception occurs in your application, it should be an object inherited from type System.Exception, and as such will have the following public members:

    HelpLinkGets or sets a link to the help file associated with this exception.
    InnerExceptionGets the Exception instance that caused the current exception.
    MessageGets a message that describes the current exception.
    SourceGets or sets the name of the application or the object that causes the error.
    StackTraceGets a string representation of the frames on the call stack at the time the current exception was thrown.
    TargetSiteGets the method that throws the current exception.

    Using the Page_Error or OnError sub

    The first line of defense in error handling happens at the page level. You can override the MyBase.Error sub as such: (Visual Studio will complete the code if you click either the Overrides or BaseClass events in the editor). The two functions you can use (one or the other, both will not work as only one will get called)

    
        Private Sub Page_Error(ByVal sender As Object, ByVal e As System.EventArgs) 
    Handles MyBase.Error
        
        End Sub
    
    
    Or you can use this one:
      
    	Protected Overrides Sub OnError(ByVal e As System.EventArgs)
    
        End Sub
    
    
    Handling errors in these subs is a simple process. Just call Server.GetLastError to return the error. If you want to redirect to a specific page here you can just call Response.Redirect ("HandleError.aspx") or whatever your page may be. This method of handling errors is good for several reasons.
    1. If you need to override the Application_Error or the customErrors setup in the web.config file
    2. If each page must implement it's own error handling If you need to log specific information and then carry on, just code for your logging or whatever here, and that is all. If you need to cancel the error processing here (so it doesn't go to the Application_Error or customErrors) simply call Server.ClearError in this sub.

    Using the global.asax File

    The global.asax file contains the next line of defense against errors. When an error occurs, the Application_Error sub is called. This location happens to be my favorite place to log errors because it is the most functional. For most of my applications in .NET, I don't handle too many custom errors at the page level. I handle them at the application level. The only two locations that actually give you access to Server.GetLastError are in the Page_Error and Application_Error subs.

    After the Page_Error is called, the Application_Error sub is called. Here you can also log the error and redirect to another page. I won't explain anything else about it because it is basically the same as the Page_Error but happens to be at the application level rather than the page level.

    Using the web.config File

    The customErrors element of the web.config file is the last line of defense against an unhandled error. If you have other error handlers in place, like the Application_Error of Page_Error subs, these will get called first. Provided they don't do a Response.Redirect or a Server.ClearError, you should be brought to the page(s) defined in the web.config. In the web.config file, you can handle specific error codes (500, 404, etc), or you can use one page to handle all errors. This is a major difference between this method and the others (although you can emulate this by doing various Response.Redirects using the other methods). Open up your web.config file. The customErrors section uses this format:

    
    <customErrors defaultRedirect="url" mode="On|Off|RemoteOnly">
       <error statusCode="statuscode" redirect="url"/>
    </customErrors>
    
    
    Here is some important information about the "mode" attribute:

    "On" specifies that custom errors are enabled. If no defaultRedirect is specified, users see a generic error.

    "Off" specifies that custom errors are disabled. This allows display of detailed errors.

    "RemoteOnly" specifies that custom errors are shown only to remote clients, and ASP.NET errors are shown to the local host. This is the default.

    By default, the section looks like this when you create a Web application.

    
    <customErrors mode="RemoteOnly" />
    
    
    This will show a generic page to users. To redirect it to one of your own pages, you would change it to this:
    
    <customErrors mode="On" defaultRedirect="error.htm" />
    
    
    Now all errors that occur will be brought to the error.htm page.

    To handle specific errors, and redirect to the error page for everything else you can specify the error code you want specially handled like so:

    
    <customErrors mode="On" defaultRedirect="error.htm">
        <error statusCode="500" redirect="error500.aspx?code=500"/>
        <error statusCode="404" redirect="filenotfound.aspx"/>
        <error statusCode="403" redirect="authorizationfailed.aspx"/>
    </customErrors> 
    
    
    There is a problem here with this solution. Once the redirect is done, your error information is no longer available on the redirected page. This is because IIS (via the .net framework) performs a plain old GET request to the error page and does not do a "Server.Transfer" like the built-in IIS error handling does.

    The only information available to you at this time is the URL that caused this error to be raised. This is located on the querystring as "aspxerrorpath": http://localhost/ErrorHandling/error500.aspx?aspxerrorpath=/ErrorHandling/WebForm1.aspx. The only places this information is available is the two methods described above.

    Another interesting point about the above customErrors element is that you can specify different error pages for different subdirectories.

    For this example, let's say you have a directory named "Customers" off of your root directory that contains a branding specific for logged in customers but is not in its own application. As such you want to define a different set of pages for errors. Please note that these pages specified in the "redirect" attribute are relative to the "Customers" subdirectory and not the root path of your site. I have also included a security rule which says only MYDOMAIN\Customers can access these files. You can define rules for these errors in the web.config file:

    
    <configuration>
       <system.web>
          ...
          ...
       </system.web>
    
       <!-- Configuration for the "Customers" subdirectory. -->
       <location path="Customers">
          <system.web>
      	<customErrors mode="On" defaultRedirect="error.htm">
    		<error statusCode="500" redirect="CustomerError500.aspx"/>
    		<error statusCode="401" 
    redirect="CustomerAccessDenied.aspx"/>
    		<error statusCode="404" 
    redirect="CustomerPageNotFound.htm"/>
    		<error statusCode="403" redirect="noaccessallowed.htm"/>
    	</customErrors>       
    	<authorization>
    		<allow roles="MYDOMAIN\Customers" />
    		<deny users="*" />
    	</authorization>
          </system.web>
       </location>
    
    
    Note: One thing I found in development is there seems to be an inheritance order for these errors. What I mean by this is if you have a 500 error defined for the root site, but none defined for the customers directory, but you DO have a defaultRedirect set for the customer directory, the 500 handler defined at the root level will be called. So if a parent directory has a handler.

    Using the Code

    I have created an application with settings, so you can get an idea of how to configure your code. In the zip file there is a solution containing two projects.

    The first is a Web project that has some buttons to cause different errors. It also shows an example of handling the error through the page, global.asax, and web.config file. There will also be a DotNetErrorLog.sql you can run in query analyzer to create a database (and user) to start logging errors ASAP.

    You will notice in my web.config I have the following:

    
     <appSettings>
    	  <add key="ErrorLoggingLogToDB" value="True" />
    	  <add key="ErrorLoggingLogToEventLog" value="True" />
    	  <add key="ErrorLoggingLogToFile" value="True" />
    	  <add key="ErrorLoggingConnectString" value="Initial 
    Catalog=DotNetErrorLog;Data Source=localhost;Integrated Security=SSPI;" />
    	  <add key="ErrorLoggingEventLogType" value="Application" />
    	  <add key="ErrorLoggingLogFile" value="c:\ErrorManager.log" />	  
      </appSettings>
    
    
    This is where I keep specific settings for an application. You do not have to worry about keeping it in the registry, and this is great for moving your applications between development, integration, and production environments (if you are blessed with that). For better security, you can incorporate the encryption classes in .NET to encrypt the database connection info and store that information in the web.config rather than the plain text connectstring, but that obviously isn't the purpose of this article. The settings pretty much are as follows:

    1. To log to a db:
      1. ErrorLoggingLogToDB - Set to "True" to tell the app you want to log info into the db
      2. ErrorLoggingConnectString - The connect string to connect to the database to store errors

    2. To log to the event log:
      1. ErrorLoggingLogToEventLog - Set to "True" to tell the app you want to log error information to the event log
      2. ErrorLoggingEventLogType - The name of the event log to log to (ex. System, Application, etc etc.). You can even create your own log just for web errors too, which could be ideal for large sites!

    3. To log to a text file:
      1. ErrorLoggingLogToFile - Set to "True" to tell the app you want to log info to a text file
      2. ErrorLoggingLogFile - The path of the file to log errors to

    Here is a sample of what to expect in the log file or the event log:

    -----------------12/20/2002 3:00:36 PM-----------------
    SessionID:qwyvaojenw1ad1553ftnesmq
    Form Data:
    __VIEWSTATE - dDwtNTMwNzcxMzI0Ozs+4QI35VkUBmX1qfHHH8i25a/4g4A=
    Button1 - Cause a generic error in the customer directory
    1: Error Description:Exception of type System.Web.HttpUnhandledException was thrown.
    1: Source:System.Web
    1: Stack Trace: at System.Web.UI.Page.HandleError(Exception e)
    1: at System.Web.UI.Page.ProcessRequestMain()
    1: at System.Web.UI.Page.ProcessRequest()
    1: at System.Web.UI.Page.ProcessRequest(HttpContext context)
    1: at System.Web.CallHandlerExecutionStep.Execute()
    1: at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
    1: Target Site:Boolean HandleError(System.Exception)
    2: Error Description:Object reference not set to an instance of an object.
    2: Source:ErrorHandling
    2: Stack Trace: at ErrorHandling.WebForm2.Button1_Click(Object sender, EventArgs e) in C:\Inetpub\wwwroot\ErrorHandling\Customers\WebForm2.aspx.vb:line 26
    2: at System.Web.UI.WebControls.Button.OnClick(EventArgs e)
    2: at System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument)
    2: at System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument)
    2: at System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData)
    2: at System.Web.UI.Page.ProcessRequestMain()
    2: Target Site:Void Button1_Click(System.Object, System.EventArgs)

    First, the date and time is logged. Secondly, the user's session id is logged. These session ids look quite different than classic asp session ids which were all numeric. The next line contains any form data on the page. This is great especially if they filled in information on the page, and that information caused your app to bomb. All of the lines with "1" in front of it are the first error. This contains the description, source, stack track and what function caused the error. Starting at the "2"s, this is the error generated before #1. Error #2 here is the "InnerException" to error one. This is a new idea here (from classic asp or vb) since it allows error information to have a hierarchy to it. Some errors can be trapped, and rethrown with a new error giving more specific information.

    Another idea is to use the SMTP component to e-mail you when an error occurs, enabling you to be proactive for errors. This would be a simple addition to the appSettings section above to hold an e-mail address and simply use the CErrorLog.GetErrorAsString to get the text needed to send an e-mail out.

    Special Notes

    - I read somewhere on the Net that someone recommended taking the error number and then looking up the proper message in a database to display to the user.

    I like this idea; however, the downside is if an unexpected database error occurs, then you have just lost your errorpage ability.

    - A quick note about performing a redirection inside a try-catch block:

    If you want to redirect to a page within a given try-catch block in your code (custom error handlers included), understand this can fail under certain circumstances because a Response.Redirect calls Response.End within its internal code, creating problems. You must call Response.Redirect("pagename.aspx",False") which specifies the redirect call and will not call Response.End, thus, preventing the exception.

    Good luck and happy error logging!

    About the Author

    Adam Tuliper's professional career involes developing .Net, COM, VB, ASP, C, C++, and SQL Server solutions for business solutions and consumer applications. He's been developing for over six years professionaly. He is also the owner of gecko software, where they develop Internet center software, system monitoring, and security scanning software. He has a degree in CIS. He also serves as a security consultant to several companies. You can reach him at amt@gecko-software.com.

  • Rate This Article
    Not HelpfulMost Helpful
    1 2 3 4 5
    Supporting Products/Tools
    CustomError 2.0 for IIS
    When errors occur on a Web site, they should be handled in a way that helps the user to get back on track. Unfortunately, setting up customized error pages in IIS usually requires something many Web developers lack -- access to and familiarity with the Web server's administrative interface. With CustomError for IIS, developers can add error pages, coded by hand or created in their favorite editor, by simply uploading them to a designated directory. No administrator intervention is required.
    [Top]
    Other Articles
    Sep 22, 2004 - Unit Test - Testing with NUnit Framework
    Kamran Qamar introduces unit testing with NUnit and offers some best practices, tips, and tricks.
    [Read This Article]  [Top]
    Aug 10, 2004 - Implementing and Promoting Daily Builds
    Automatic daily builds is a well known software engineering best practice. This article introduces a strategy for implementing and promoting daily builds and offers tips and tricks for preventing and fixing breaks.
    [Read This Article]  [Top]
    Jun 21, 2004 - Using Open Source .NET Tools for Sophisticated Builds
    Building an application can be more than pressing F5. With an increasing number of quality packages being released, developers for the .NET platform now have options to create a very sophisticated build process. Aaron Junod describes a sample build environment and shows how a number of tools can work together to make reliable, predictable, and value-added builds.
    [Read This Article]  [Top]
    Jun 18, 2003 - Online Database Functions Testing Tool
    This short article provides source code for a classic ASP online database functions testing application and shows how to configure and use the tool for either SQL Server or Oracle.
    [Read This Article]  [Top]
    Sep 10, 2002 - Tracing in .NET and Implementing Your Own Trace Listeners
    Mansoor Ahmed Siddiqui explains debugging and tracing and shows how to create custom trace listeners to help ensure hassle-free development.
    [Read This Article]  [Top]
    Sep 5, 2001 - Firing Events in a Shared Hosting Environment
    Firing events on a Web server is an easy task. However most of the easy solutions require you to have your own dedicated IIS or SQL Server on the Internet to play with, a privilege not shared by many. In this article, Matthew Muller shows you how to get the same functionality in a shared hosting environment.
    [Read This Article]  [Top]
    May 25, 2001 - Avoiding a Type Mismatch Error When Using ByRef with ASP and COM
    Unlike programming inside a complete VB system, when using ByRef with ASP and COM, a complication arises because ASP's VBScript is not typed, but the component's VB is typed. This article will briefly explain how ByRef can be used with ASP and COM.
    [Read This Article]  [Top]
    Apr 18, 2001 - Error Reporting - IIS 5.0
    The script in Mark Newlands' article this week handles how errors are displayed and logged. It can capture all values in use at the time (e.g. form, querystring, session,and application level) and records them if you set a Boolean value to do so - displays custom HTML if required. Sends email, logs to database, and/or text file.
    [Read This Article]  [Top]
    Mar 12, 2001 - Transact-SQL Improves Database Error-Handling
    Transact-SQL provides developers with several database error-handling methods. Use these functions to efficiently handle database errors and add an extra level of data validation. This article discusses the @@ERROR, SP_ADDMESSAGE, and RAISERROR functions and provides examples on how to implement them.
    [Read This Article]  [Top]
    Feb 2, 2001 - Solving a Caching And Expiring Problem
    Read what advice members of the 15Seconds Discussion list had to offer on forcing pages to refesh, even when the user hits the back button.
    [Read This Article]  [Top]
    Mailing List
    Want to receive email when the next article is published? Just Click Here to sign up.

    Support the Active Server Industry



    JupiterOnlineMedia

    internet.comearthweb.comDevx.commediabistro.comGraphics.com

    Search:

    Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

    Jupitermedia Corporate Info


    Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

    Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers

    Solutions
    Whitepapers and eBooks
    Microsoft Article: Will Hyper-V Make VMware This Decade's Netscape?
    Microsoft Article: 7.0, Microsoft's Lucky Version?
    Microsoft Article: Hyper-V--The Killer Feature in Windows Server 2008
    Avaya Article: How to Feed Data into the Avaya Event Processor
    Microsoft Article: Install What You Need with Windows Server 2008
    HP eBook: Putting the Green into IT
    Whitepaper: HP Integrated Citrix XenServer for HP ProLiant Servers
    Intel Go Parallel Portal: Interview with C++ Guru Herb Sutter, Part 1
    Intel Go Parallel Portal: Interview with C++ Guru Herb Sutter, Part 2--The Future of Concurrency
    Avaya Article: Setting Up a SIP A/S Development Environment
    IBM Article: How Cool Is Your Data Center?
    Microsoft Article: Managing Virtual Machines with Microsoft System Center
    HP eBook: Storage Networking , Part 1
    Microsoft Article: Solving Data Center Complexity with Microsoft System Center Configuration Manager 2007
    MORE WHITEPAPERS, EBOOKS, AND ARTICLES
    Webcasts
    Intel Video: Are Multi-core Processors Here to Stay?
    On-Demand Webcast: Five Virtualization Trends to Watch
    HP Video: Page Cost Calculator
    Intel Video: APIs for Parallel Programming
    HP Webcast: Storage Is Changing Fast - Be Ready or Be Left Behind
    Microsoft Silverlight Video: Creating Fading Controls with Expression Design and Expression Blend 2
    MORE WEBCASTS, PODCASTS, AND VIDEOS
    Downloads and eKits
    Sun Download: Solaris 8 Migration Assistant
    Sybase Download: SQL Anywhere Developer Edition
    Red Gate Download: SQL Backup Pro and free DBA Best Practices eBook
    Red Gate Download: SQL Compare Pro 6
    Iron Speed Designer Application Generator
    MORE DOWNLOADS, EKITS, AND FREE TRIALS
    Tutorials and Demos
    How-to-Article: Preparing for Hyper-Threading Technology and Dual Core Technology
    eTouch PDF: Conquering the Tyranny of E-Mail and Word Processors
    IBM Article: Collaborating in the High-Performance Workplace
    HP Demo: StorageWorks EVA4400
    Intel Featured Algorhythm: Intel Threading Building Blocks--The Pipeline Class
    Microsoft How-to Article: Get Going with Silverlight and Windows Live
    MORE TUTORIALS, DEMOS AND STEP-BY-STEP GUIDES