I have blogged before about liking Enterprise Library, particularly about its exception handling mechanism. Given that the whole purpose of the exception handling mechanism is to provide much needed information about defects in software I have recently been faced with a problem where the exception handling mechanism itself failed.

I had a piece of software that was deployed to a production server. It had been tested fully on a staging environment and was then deployed. It failed, in that it apparently did nothing when a request was sent. We log exceptions into the database but that was empty, I configured an exception handler that writes to the Event Log, once again nothing. Hmm it looked as though I was a victim of Systemantics, specifically the Fail Safe Theorem:

The Fail-Safe Theorem: When a Fail-Safe system fails, it fails by failing to fail safe.

The problem could be a real problem in the software, for example we were not calling the exception handler or it could be a problem in exception handler itself, or it could be that the request was not getting through. I needed to isolate where the problem was. The usual mechanism for doing this was to use the exception handling mechanism, however as this was the first time I had deployed to this server I needed some kind of sign that the mechanism was working.

I have had issues like this in the past and it is hard to find a logging mechanism that can be relied on completely.

A database logging exception handler is susceptible to having database client software, network connection and connection credentials.

A Event Log exception handler is susceptible to security issues, many production environments disallow access to the Event Log as it can contain sensitive information.

The most reliable and simplest solution I could think of was a Debug Console exception handler, that is an exception handler that writes to the debug console. The debug console is a good choice as it is guaranteed to be there, it is rarely restricted, and it can be monitored without the need to install any software on the server. It can be monitored either locally or remotely using a number of tools but the one I tend to use is DebugView from Microsoft Sysinternals. The advantage of DebugView is that it can be run remotely or locally without the need to install anything, just copy the single exe.

The Enterprise Library Exception Handler is very straightforward to write, this is the complete code.

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration;

namespace AAD.ProvidersLibrary
{
  [ConfigurationElementType(typeof(CustomHandlerData))]
  public class DebugConsoleExceptionHandler : IExceptionHandler
  {
    public DebugConsoleExceptionHandler(NameValueCollection ignore)
    {
    }

    public Exception HandleException(
                              Exception exception, 
                              Guid handlingInstanceId
                           )
    {
      OutputToConsole("Exception Start");
      OutputToConsole(
          string.Format("ID: {0}, Message: {1}",
                   handlingInstanceId.ToString(),
                   exception.Message));
      OutputToConsole("Exception End");

      return exception;
    }

    protected virtual void OutputToConsole(
                              string format,
                              params object[] args
                           )
    {
      Debug.Print(format, args);
    }
  }
}

To show how this can be used I wrote a very simple program that just throws an exception like this.

class Program
  {
    static void Main(string[] args)
    {
      Debug.Print("Program Start");

      System.Exception ex = new Exception("A test exception");
      ExceptionPolicy.HandleException(ex, "AAD Policy");

      Console.WriteLine("Done.");
    }
  }

I have also implemented a Broken Exception Handler to simulate what might happen with a handler that was not working

namespace AAD.ProvidersLibrary
{
  [ConfigurationElementType(typeof(CustomHandlerData))]
  public class BrokenExceptionHandler : IExceptionHandler
  {
    public BrokenExceptionHandler(NameValueCollection ignore)
    {
      //throw new Exception("CONSTRUCTOR FAILURE");
    }

    public Exception HandleException(Exception exception, Guid handlingInstanceId)
    {
      throw new Exception("HANDLER FAILURE");
      return exception;
    }
  }
}

Then I can configure both handlers into the Enterprise Library Policy in the enterprise library configuration either in app.config, web.config or it may be in its own separate config file like this (I have also configured in the standard Event Log handler).

<exceptionhandling>
  <exceptionpolicies>
    <add name="AAD Policy">
      <exceptiontypes>
        <add name="Exception"
                posthandlingaction="None"
                type="System.Exception, mscorlib, Version=2.0.0.0,
                           Culture=neutral,
                           PublicKeyToken=b77a5c561934e089">
          <exceptionhandlers>
            <add name="Custom Debug Console Handler"
              type="AAD.ProvidersLibrary.DebugConsoleExceptionHandler,
                      ExceptionHandler, Version=1.0.0.0, Culture=neutral,
                      PublicKeyToken=null" />
            <add name="Custom Handler"
              type="AAD.ProvidersLibrary.BrokenExceptionHandler,
                      ExceptionHandler, Version=1.0.0.0, Culture=neutral,
                      PublicKeyToken=null" />
            <add title="Enterprise Library Exception Handling"
                    name="Logging Handler"
                    type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.LoggingExceptionHandler,
                         Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging,
                         Version=4.0.0.0,
                         Culture=neutral,
                         PublicKeyToken=31bf3856ad364e35" 
                     usedefaultlogger="false" priority="0" 
                     formattertype="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.XmlExceptionFormatter,
                         Microsoft.Practices.EnterpriseLibrary.ExceptionHandling,
                         Version=4.0.0.0,
                         Culture=neutral,
                         PublicKeyToken=31bf3856ad364e35" 
                     severity="Error"
                     eventid="100"
                     logcategory="Exceptions" />
          </exceptionhandlers>
        </add>
      </exceptiontypes>
    </add>
  </exceptionpolicies>
</exceptionhandling>

Please note that the Debug Console handler is physically the first handler in the file, this does give the best chance of seeing an exception.

When the program is run and the exception fires, nothing is written by Enterprise Library to the Event Log. There may be something in the event log if the OS has detected your program aborting but its unlikely to be very useful, this is what I got from a standard EXE application domain.

Log Name:      Application
Source:        Windows Error Reporting
Date:          24/08/2010 20:25:11
Event ID:      1001
Task Category: None
Level:         Information
Keywords:      Classic
User:          N/A
Computer:      -----
Description:
Fault bucket , type 0
Event Name: CLR20r3
Response: Not available
Cab Id: 0

Problem signature:
P1: 0V0DMNGI4KP0FD2NOHG4YSFBQA5APTTZ
P2: 1.0.0.0
P3: 4c741c71
P4: Microsoft.Practices.EnterpriseLibrary.ExceptionHandling
P5: 4.0.0.0
P6: 482b76b4
P7: 12d
P8: c9
P9: FUBV21AXAANWXNW1H1IUFLUXEZ1Y44LQ
P10: 

Attached files:

These files may be available here:
C:\ProgramData\Microsoft\Windows\WER\ReportArchive\AppCrash_0V0DMNGI4KP0FD2N_33286785ea64748539fd1471e8a8a0802f19e2fa_04a543a6

Analysis symbol: 
Rechecking for solution: 0
Report Id: 4df7eb32-afb5-11df-9817-001ec902ae30
Report Status: 0

However this is what we see in DebugView

dbgview

Enterprise library calls the HandleException method in each of the handlers in turn but the chain is broken if one of them fails. In this instance the “Custom Debug Console Handler” records the exception in the debug console. The “Custom Handler”, which is a broken handler, in this example it is taking the place of a handler that may not be working in a production environment is then called and throws an exception so the “Logging Handler” is never called.

My first reaction is to move the “Logging Handler” up the chain, in other words making it physically the first <add> element in the <exceptionhandlers> however there have been instances where event logging is not permitted in a hosted production environment.

This is where the “Custom Debug Console Handler” comes in its a great little handler that can be used to check if there is a problem in any of the configured exception handlers.

Its worth noting that if I uncomment the
throw new Exception("CONSTRUCTOR FAILURE");
code in the broken handler then Enterprise Library throws an exception when constructing the policy and none of the HandleException methods get called, with this in mind I try and keep to a minimum the code in the exception handler constructor.