Click here to Skip to main content
15,867,568 members
Articles / Web Development / ASP.NET

Logging Unhandled Exceptions in an ASP.NET Website

Rate me:
Please Sign up or sign in to vote.
4.42/5 (8 votes)
14 Jan 2011CPOL5 min read 63.2K   1.5K   36   5
Logging unhandled exceptions in an ASP.NET website using MS Enterprise Application Blocks.

Introduction

When developing an ASP.NET application, one of the routine tasks is to plan for unhandled exceptions. If the exception is left unhandled, by default, the ASP.NET runtime will either display a nasty error message to your user or it will show the exception details page, depending on how you configure your website. Allowing the user to see a nasty error messages is far from recommended (see this article for exception handling best practices). If you simply show a generic exception details page, you will lose valuable information you may need to debug the issue.

For a few years, I have been using this strategy for processing unhandled exceptions in my websites. When an unhandled exception occurs, the strategy is to:

  • Catch the error in the application-level Error event handler (Global.asax).
  • "Process" the error by sending an email containing the exception details.
  • Redirect to a custom webpage displaying a user-friendly message to the end user.

Now, I am not suggesting that you should not use try catch blocks in your code to catch errors where you can recover. This is a strategy for catching those unexpected errors in one central location, logging the exception information, sending an email to a developer, and displaying a friendly message to your user.

The problem with the approach I have been using is that it leaves the logging and sending of an email up to you to manually implement. In fact, I was only sending out an email with the error message and relying on the server's application logs to record the errors. Tracking down the problem, who the user was, etc., became a real pain using only an email message and application logs. I wished for an easier way to receive a notice of an error and a way to store the information so that I could run a report to view the errors or even see some statistics.

So, I started doing some research on the Microsoft Enterprise Application blocks, and thought that they were exactly what I was looking for. This article in particular was very helpful, and you may want to follow this approach for your N-Tiered applications.

What I love about using the application blocks is that you simply enter a few settings in the web.config file, add references to the application blocks, and with a few lines of code, I was sending emails and logging exceptions to SQL Server. Next, one quick Reporting Services report later, and I could easily view the information in the Logging database!

Using the code

What you will need to use this code:

  • MS Enterprise Library 5.0
  • Must be using at least .NET Framework 3.5
  • SQL Server - with the Enterprise Library Logging database installed

From the MS Enterprise Library documentation:

"In the folder where you installed the Enterprise Library, open the subfolder Source\Blocks\Logging\Src\DatabaseTraceListener\Scripts in Windows Explorer. This folder contains a SQL script named LoggingDatabase.sql and a command file named CreateLoggingDb.cmd that executes this script. The script creates a new database named Logging, and adds to it all of the tables and Stored Procedures required by the database trace listener to write log entries to a database."

Add references to the following application blocks (should be located at C:\Program Files (x86)\Microsoft Enterprise Library 5.0\Bin\):

  • Microsoft.Practices.EnterpriseLibrary.Common.dll
  • Microsoft.Practices.EnterpriseLibrary.Data.dll
  • Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.dll
  • Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.dll
  • Microsoft.Practices.EnterpriseLibrary.Logging.dll
  • Microsoft.Practices.EnterpriseLibrary.Logging.Database.dll

After you install the MS Enterprise Library, when you right click on the web.config file in Visual Studio, you will see a menu option for Edit Enterprise Library V5 Configuration. You can use this tool to enter the necessary configuration info, or you can do it by manually updating the web.config file. I strongly recommend the former especially if you are new to using the application blocks. For the purposes of this article, under the Blocks menu, choose Add Logging Settings and Add Exception Handling Settings. By default, you should already have Application Settings and Database Settings. After you have those added, you can close and save the tool, which will update your web.config file.

For simplicity, update the web.config with this code snippet. You can then go back to the tool to more easily see the settings. Make sure to update the email addresses and STMP server in the Logging Settings and the connection string for the Logging database under Database Settings.

The snippet below has been wrapped to avoid page scrolling.

XML
<configsections />
  <section name="loggingConfiguration" requirepermission="true" 
     type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, 
           Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, 
           Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  <section name="exceptionHandling" requirepermission="true" 
     type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.
           Configuration.ExceptionHandlingSettings, 
           Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, 
           Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
...
</configsections />
<loggingconfiguration tracingenabled="true" 
             defaultcategory="General" />
  <listeners />
    <add name="Email Trace Listener" 
        type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.
              EmailTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, 
              Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        listenerdatatype="Microsoft.Practices.EnterpriseLibrary.Logging.
                          Configuration.EmailTraceListenerData, 
                          Microsoft.Practices.EnterpriseLibrary.Logging, 
                          Version=5.0.414.0, Culture=neutral, 
                          PublicKeyToken=31bf3856ad364e35" 
        toaddress="someone@yourcompany.com" 
        fromaddress="noreply@yourcompany.com" 
        subjectlineender="- Log Example Website" 
        smtpserver="YourSMTPServer" 
        formatter="Email Text Formatter" 
        traceoutputoptions="DateTime, Timestamp, ProcessId, Callstack" />
    <add name="Database Trace Listener" 
      type="Microsoft.Practices.EnterpriseLibrary.Logging.Database.
            FormattedDatabaseTraceListener, 
            Microsoft.Practices.EnterpriseLibrary.Logging.Database, 
            Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" 
      listenerdatatype="Microsoft.Practices.EnterpriseLibrary.Logging.
                        Database.Configuration.FormattedDatabaseTraceListenerData, 
                        Microsoft.Practices.EnterpriseLibrary.Logging.Database, 
                        Version=5.0.414.0, Culture=neutral, 
                        PublicKeyToken=31bf3856ad364e35" 
      formatter="Text Formatter" 
      traceoutputoptions="LogicalOperationStack, DateTime, 
                          Timestamp, ProcessId, ThreadId, Callstack" 
      databaseinstancename="LoggingConnectionString" 
      writelogstoredprocname="WriteLog" 
      addcategorystoredprocname="AddCategory" />
  </listeners />
  <formatters />
    <add name="Text Formatter" 
      type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, 
            Microsoft.Practices.EnterpriseLibrary.Logging, 
            Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" 
       template="Application Name: Log Example Website
       Message: {message}{newline}
       Category: {category}{newline}
       Extended Properties: {dictionary({key} - {value}{newline})}" />
    <add name="Email Text Formatter" 
      type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, 
            Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, 
            Culture=neutral, PublicKeyToken=31bf3856ad364e35" 
      template="There was an error. Please see the Logging database 
                for more information. Timestamp: {timestamp(local)}
                {newline} Message: {message}{newline}" />
  </formatters />
  <categorysources />
    <add name="ErrorLogging" switchvalue="All" />
      <listeners />
        <add name="Email Trace Listener" />
        <add name="Database Trace Listener" />
      </listeners />
    </add />
  </categorysources />
  <specialsources />
    <allevents name="All Events" switchvalue="All" />
    <notprocessed name="Unprocessed Category" switchvalue="All" />
    <errors name="Logging Errors & Warnings" switchvalue="All" />
    <listeners />
      <add name="Email Trace Listener" />
      <add name="Database Trace Listener" />
    </listeners />
    </errors />
  </specialsources />
 </loggingconfiguration />
 <exceptionhandling />
  <exceptionpolicies />
   <add name="AllExceptionsPolicy" />
    <exceptiontypes />
     <add name="All Exceptions" 
        type="System.Exception, mscorlib, Version=2.0.0.0, 
              Culture=neutral, PublicKeyToken=b77a5c561934e089" 
        posthandlingaction="None" />
      <exceptionhandlers />
       <add title="Enterprise Library Exception Handling" 
         name="AllExceptionsLoggingHandler" 
         type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.
               Logging.LoggingExceptionHandler, Microsoft.Practices.
               EnterpriseLibrary.ExceptionHandling.Logging, 
               Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" 
         logcategory="ErrorLogging" 
         eventid="100" severity="Error" 
         formattertype="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.
                        TextExceptionFormatter, 
                        Microsoft.Practices.EnterpriseLibrary.ExceptionHandling" 
         priority="0" />
      </exceptionhandlers />
     </add />
    </exceptiontypes />
   </add />
  </exceptionpolicies />
 </exceptionhandling />
 <connectionstrings />
  <add name="LoggingConnectionString" 
     connectionstring="Data Source=YourSQLServer;
                       Initial Catalog=Logging;
                       Integrated Security=SSPI" 
     providername="System.Data.SqlClient" />
 </connectionstrings />

Place this code in the Global.asax file:

C#
protected void Application_Error(object sender, EventArgs e)
{
    //uncomment in order to bypass logging when running locally.
    //if (!Request.IsLocal)
    //{
        Exception ex = Server.GetLastError();
        if (ex is HttpUnhandledException && ex.InnerException != null)
        {
            ex = ex.InnerException;
        }

        if (ex != null)
        {
            Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.
               ExceptionPolicy.HandleException(ex, "AllExceptionsPolicy");
            Server.ClearError();

            Response.Redirect("~/Utility/ErrorPage.htm");
        }
    //}
}

As you can see from the code above, after the error is handled by the application block, the user will be redirected to the ~/Utility/ErrorPage.htm page. So, you will need to create a page for your site, or you can use the one in the sample code for download in this article.

So, that is all there is to using the MS Enterprise Application Blocks to process unhandled exceptions in an ASP.NET website. Download the sample code, which contains a project to demo how to process unhandled exceptions. If you are familiar with SQL Server Reporting Services, you can create your own custom reports to view the data logged to SQL Server.

In closing, this is my first article so any feedback would be greatly appreciated. I hope someone finds it helpful... Thanks!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questionemail with HTML template Pin
kiquenet.com26-Sep-15 3:15
professionalkiquenet.com26-Sep-15 3:15 
AnswerRe: email with HTML template Pin
mgoad9928-Sep-15 5:18
mgoad9928-Sep-15 5:18 
GeneralNice article Pin
bbirajdar18-Nov-13 18:09
bbirajdar18-Nov-13 18:09 
QuestionExample for logging exception in application database rather than separate database Pin
Flying Kite20-Sep-11 7:40
Flying Kite20-Sep-11 7:40 
Generalhelpfull Pin
Pranay Rana26-Jan-11 23:14
professionalPranay Rana26-Jan-11 23:14 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.