Exception Management


Guidance on managing exceptions

 

An exception is something you do not expect to happen in your application, there are two types of exception fatal and nonfatal.  Fatal exceptions is anything that you did not define or not based from the ApplicationException class.

 

Your applications should always define at least one or more ApplicationException types so you can inform the application of broken business rules, non fatal exceptions are not warnings they are unexpected events, to tell the caller something went wrong.

 

Let’s start with the following code for this example:

 

using System;

using System.Collections;

 

namespace blogs.msdn.com.eferron

{

  class BlogExceptionCode

  {

    [STAThread]

    static void Main(string[] args)

    {

      ArrayList listOfColors = null;

      string selectedColor = String.Empty;

 

      listOfColors = new ArrayList();

 

      listOfColors.Add(“red”);

      listOfColors.Add(“blue”);

      listOfColors.Add(“green”);

 

      // select a color and display it

      selectedColor = (string)listOfColors[2];

      Console.WriteLine(selectedColor);

 

      // this line throws an ArgumentOutOfRangeException

      selectedColor = (string)listOfColors[3];

      Console.WriteLine(selectedColor);

     

      Console.ReadLine();

     

    }

  }

}

 

 

The line of code that attempts to access the fourth element in the ArrayList will throw an ArgumentOutOfRangeException exception.  The code below shows a very common mistake I see in line of business applications.

try

{

  selectedColor = (string)listOfColors[3];

}

catch(Exception ex)

{

  MessageBox.Show(ex.Message);

  // …

  // other code sometimes appear in here in different

  // customer scenarios

}

 

Console.WriteLine(selectedColor);

Console.ReadLine();

 

 The exception displayed comes from the framework, it displays some unknown cryptic message the user can do nothing about.  In your line of business applications never ship this code (code which displays a fatal exception in a MessageBox to your customers). 

 

Note: You laugh now but I have seen this time and time again.

 

The only exception type that should ever been seen in a display is one that derives from ApplicationException.  You can assure these are application specific exceptions an in many cases non fatal, that may provide the user with useful information, which does not expose sensitive system information.

 

Define at least one (in many cases several ) custom types derived from ApplicationException

 

I will define a custom exception that contains a friendly error message, which I can safely display to the customer.

 

public class ColorDoesNotExistException : ApplicationException

{

  public ColorDoesNotExistException(){}

  public ColorDoesNotExistException(string Message)

    :base(Message){}

  public ColorDoesNotExistException(string Message, Exception InnerException)

    :base(Message, InnerException){}

}

 

In effort to make the example make a little bit of refactoring is order so the example makes sense.  We will add a ColorList (server) class and FakeForm (client) class

 

public class FakeForm

{

  public FakeForm(){}

 

  public void SomeClickEvent()

  {

    ColorList colorList = null;

    string selectedColor = String.Empty;

 

    colorList = new ColorList();

    try

    {

      selectedColor = colorList.SelectColor(2);

      Console.WriteLine(“You selected the color {0}”, selectedColor);

 

      // this line throws the exception

      selectedColor = colorList.SelectColor(3);

      Console.WriteLine(“You selected the color {0}”, selectedColor);

 

    }

    catch(ArgumentOutOfRangeException systemException)

    {

      throw new ColorDoesNotExistException(“Please select a valid color …”, systemException);

    }

    catch(Exception)

    {

      // this is a great place to add some debug trace statements

      // consider using trace switches for verbose logging in tough

      // debugging scenarios

      throw;

    }

  }

}

 

public class ColorList

{

  private ArrayList _listOfColors;

  public ColorList()

  {

    _listOfColors = new ArrayList();

    _listOfColors.Add(“red”);

 

    _listOfColors.Add(“blue”);

    _listOfColors.Add(“green”);

  }

 

  public string SelectColor(int colorIndex)

  {

    if (colorIndex < 0 || colorIndex > 2)

      throw new ArgumentOutOfRangeException(“colorIndex”);

 

    return (string)_listOfColors[colorIndex];

  }

}

 

Notice we catch the system exception and throw an exception based on a business rule.

 

Now for the final point: Centralized exception management:

 

In our Main method we will simulate centralized exception management.  Notice the try/catch block around the call into the client form.  I have included a few references on doing this in a Windows and Web app.  Take a look at the revised code below.

 

class BlogExceptionCode

{

  [STAThread]

  static void Main(string[] args)

  {

    FakeForm presentation = null;

    presentation = new FakeForm();

 

    // Represents our global exception management

    try

    {

      presentation.SomeClickEvent();

    }

    catch(ApplicationException nonFatalException)

    {

      // safe to display this message to the user

      // we are just indicating a business rule was broken.

      // The user can most likely fix the issue here.

      MessageBox.Show(nonFatalException.Message,”Invalid color selected”);

 

      // think about instrumentation with trace switches

      // like the verbose switch for tough debugging scenarios

    }

    catch(Exception fatalException)

    {

      MessageBox.Show(“Please call the help desk (800) 555-1212\nClick OK to restart the application.”, “An unexpected error occurred in the BlogSampleApp.”);

      // now do some type of logging to capture the fact

      // a fatal exception was generated.

      Trace.WriteLine(fatalException.Message);

    }

 

    Console.WriteLine(“Press any key to exit the application”);

    Console.ReadLine();

  }

}

 

Centralized exception management allows you to perform consistent exception management, and instrumentation for your entire application.  When you application encounters a fatal exception you should give the users a message letting them know the following things:

 

An unexpected error occurred

Who they can contact or where they can get help

The option to either shutdown or restart the application after clicking OK.

 

Optionally you can (should) develop a strategy to log the fatal exception or send the information to a repository so you can diagnose problems later.

 

In a windows application you can use the ThreadException event handler, in an ASP.NET application you should use the HttpApplication.Error event handler to capture exceptions in a central location.  This example will provide a few examples for WinForm applications.

 

Additional Resources

 

.NET Framework documentation – HttpApplication.Error event handler

(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemWebHttpApplicationClassErrorTopic.asp)

 

MSDN Magazine – Unexpected errors

By Jason Clark

(http://msdn.microsoft.com/msdnmag/issues/04/06/NET/default.aspx)

 

ASP.NET – Global Error handling

By Jonathan Goodyear, Brian Peek, and Brad Fox

(http://www.developer.com/net/asp/article.php/961301)

 

 


Comments (3)

  1. JaD says:

    I have a ton of services running without user interaction, and when I analyze my project with FxCop the only errors that remain are "types of System.Exception" are not caught.

    My question is this:

    I have over 10 services that do their job well, but every so often the data layer that we use (its code generated) will spew an error which is unexpected or some other component may throw an error, I am catching the generic System.Exception because sometimes an error may crop with a single record during massive batch operations, I want the service to continue gracefully. Our error logging mechanism is sophisticated, errors logged in the database, in text files, email notifications and you can even listen on a socket.

    I have searched and searched for best practices for Windows Services but have not found any examples. Currently my solution works, i.e. if a massive operation is going on, for instance one of my services just performs optical character recognition on thousands of image files, every now and then the OCR component might hiccup or a file archive may messup, I catch the System.Exception and continue iterating over the collection. This seems to be my only way out since I can’t accurately predict every single exception type that may happen. My only choice is to catch the generic System.Exception.

    FxCop screams about this but I have not found any other recourse since if an unhandled exception occurs, the service does not continue.

    Do you have any advice on how to manage exceptions with services that have no user interaction? I can’t use ThreadException Handler in Windows Services… Any feedback would be appreciated.

  2. Using ApplicationException is actually discouraged these days:

    http://blogs.msdn.com/brada/archive/2004/03/25/96251.aspx

    In any case, even if you think the guidelines are wrong and ApplicationException is a great idea, it still has nothing to do with the severity of the exception (fatal vs. non-fatal). For example, you could have a non-fatal UnauthorizedAccessException (user attempted to open a file that is read-only) or a fatal ApplicationException (if it is thrown from a static constructor or some piece of code that is not exception-safe).

  3. I think I have a tendancy to agree with you Pavel. Exception severity has more to do with context of the application and the requirement (or business rule) versus the type of Exception thrown. However the ApplicatonContext does provide a means of consistency across applications and a generic try/catch design pattern by just catching the ApplicationException. I read brad’s blog and I simply disagree. Creating your own Exception derived from System.Exception either forces back into the ApplicationException block pattern (except you replace ApplicationException with your own), or you have lots of custom exceptions based off of system exception. I think the second option is less than ideal and makes it a bit harder (not impossible) just harder to provide app developers with a consistent and generic design/implementation. Much like my entry Brad’s is a point of view more than a corporate stance. I respect that point of view, even though I disagree with the reasoning of it just adds an extra layer. I am of the mindset It provides a consistent distinction.