Using the Exception Handling Block in Enterprise Library 3.0

y default, the .NET Framework includes a number of classes that convey information about exceptions generated by the application. Whenever an error occurs in a .NET application, the .NET Framework catches it and raises the associated exception to the application. It is up to the application to catch that exception, process it, and inform users of the error condition in a graceful manner. But not all layers of an application are directly in contact with users. That implies that you might want to have different exception handling strategies for different application layers. Building an effective strategy for dealing with errors in various application layers requires you to write a considerable amount of reusable boilerplate code?which makes exception handling an ideal topic for a reusable library.

To fill that need, the “patterns & practices” team at Microsoft created the Exception Handling block as an integral component of Enterprise Library 3.0. Here, you’ll see examples of using it with Visual Studio to write robust and fault-tolerant .NET applications.

The Exception Handling Application Block
The Exception Handling block provides a flexible and extensible exception handling mechanism that you can use in all layers of an application. It supports a number of predefined exception handling procedures (also known as policies); these include logging an exception, propagating an exception, wrapping an exception, replacing an exception with another exception, and so on. As a developer, you just need to choose an exception policy, specify it declaratively in your application’s configuration file, and Enterprise Library handles all the rest of the work for you.

?
Figure 1. Dependencies of the Exception Handling Block: In addition to the core assemblies, the exception handling block references the Logging Block, which in turn depends on the Data Access block if you log to a database.

After you download and install Enterprise Library 3.1 May 2007 edition, you’ll find the Exception Handling block assemblies in the :Program FilesMicrosoft Enterprise Library 3.1?May 2007Bin folder.

To use the basic features of the Exception Handling block, you need to reference the Microsoft.Practices.EnterpriseLibrary.Common.dll and Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.dll assemblies. If you need logging capabilities from within your exception management block, you will also need to reference the Microsoft.Practices.EnterpriseLibrary.Logging.dll assembly. Finally, to handle exceptions in Windows Communication Service (WCF)-based services using the Exception Handling block, you have to reference the Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF.dll assembly as well. Figure 1 shows the dependencies of the Exception Handling block.

A Basic Logging Example
Here’s a basic example that shows the steps involved in configuring the Exception Handling block and using it to handle exceptions. To begin, create a new Visual C# Windows Application named ExceptionManagementBlockExample. After creating the project, navigate to the :Program FilesMicrosoft Enterprise Library 3.1?May 2007Bin folder and add these two required assembly references to the project:

  • Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.dll
  • Microsoft.Practices.EnterpriseLibrary.Common.dll

Open the default form’s code file, and import the following core exception handling namespace:

   using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;  

Add an application configuration file (app.config) to the project, and modify it to look as follows:

               

The preceding configuration file declares an exception policy named “Global Policy” that is implemented by a custom exception handler class named AppExceptionHandler. The custom exception handler implements the HandleException() method of the IExceptionHandler interface. Whenever a client application invokes the Exception Handling block with the global policy, the block invokes the AppExceptionHandler.HandleException() method. Here’s the custom handler code:

   using System;   using System.Collections.Specialized;   using System.Windows.Forms;   using Microsoft.Practices.EnterpriseLibrary      .Common.Configuration;   using Microsoft.Practices.EnterpriseLibrary      .Common.Configuration.ObjectBuilder;   using Microsoft.Practices.EnterpriseLibrary      .ExceptionHandling;   using Microsoft.Practices.EnterpriseLibrary      .ExceptionHandling.Configuration;      namespace ExceptionManagementBlockExample   {     [ConfigurationElementType(typeof(CustomHandlerData))]     public class AppExceptionHandler : IExceptionHandler     {         public AppExceptionHandler(            NameValueCollection ignore) {}              public Exception HandleException(            Exception exception, Guid correlationID)         {            DialogResult result =                this.ShowThreadExceptionDialog(exception);            //Exits the program when the user clicks Abort            if (result == DialogResult.Abort)               Application.Exit();            return exception;         }            // Creates the error message and displays it         private DialogResult ShowThreadExceptionDialog(Exception e)         {            string errorMsg = e.Message;            return MessageBox.Show(errorMsg, "Application Error",                MessageBoxButtons.OK, MessageBoxIcon.Warning);         }      }   }

The HandleException() method invokes a private helper method named ShowThreadExceptionDialog that displays the error information in a message box.

Now you can add some code to invoke the Exception Handling block. Add a button named btnProcessException to the default form, and modify its Click event to look as follows:

   private void btnProcessException_Click(      object sender, EventArgs e)   {      try      {         throw new Exception ("This is a sample exception");      }      catch (Exception ex)      {         bool rethrow = ExceptionPolicy.HandleException(            ex, "Global Policy");         if (rethrow)         {            throw;         }      }   }
?
Figure 2. Output Produced by the Custom Exception Handler Class: The ExceptionManagementBlockExample.AppExceptionHandler class inherits from the IExceptionHandler interface and implements this simple MessageBox as the custom exception behavior.

The ExceptionPolicy.HandleException() method is the core of the Exception Handling block; you invoke it to process exceptions, supplying as arguments the generated exception as well as the name of the policy you want to apply. The Exception Handling block associates the supplied policy name (“Global Policy” in this case) to the appropriate exception handler?defined by configuration file entries.

Figure 2 shows the output produced when you click on the “Process Exception” button.

Using Policy-Based Exception Handling
The previous example showed how to create a policy named “Global Policy” and map that to a custom exception handler that implements the policy logic. This section examines how the Exception Handling block simplifies the process by providing built-in policies that you can use to process run-time exceptions.

You need the same boilerplate code to handle an exception as in the previous example:

   try   {      //Some code   }   catch(Exception ex)   {      bool rethrow = ExceptionPolicy.HandleException         (ex, );      if (rethrow)         throw;   }

Remember, the second argument to the HandleException() method is the name of the policy that you would like to apply for processing the exception. By default, the Exception Handling block ships with the policies shown in Table 1.

Table 1: Built-In Exception Policies: These four policies ship with the Exception Handling block.
Policy Description
Logging Policy As the name suggests, this policy lets you log formatted exception information in locations as specified in the configuration file.
Replace Policy This policy is useful when you want to replace the original exception with another exception for security reasons.
Wrap Policy This policy lets you wrap an exception within a different exception; in other words, this policy creates a new exception of a defined type and sets the original exception as the InnerException object of the new exception.
Propagate Policy This policy allows you to propagate an exception up through the call stack so that other layers of the application can process the exception.

In addition to these policies, you can specify a custom policy name, and then implement a corresponding exception handler class to process the exceptions as shown previously.

Using Logging Policy
With that overview in mind, here’s a more in-depth look at the code required to log exceptions using logging policies. First, add the “Log Only Policy” element as a child element of the element in the app.config file.

                                         

Just as with the exception policies, you specify the logging configuration information (such as the log store, log formatting information, and so on) in the app.config file. This example adds the entries to the app.config file required to use the event log as the log store. For a full example of this configuration, check out the app.config file in the downloadable code for this article.

Now add a CommandButton named btnLogException to the form, and modify its Click event as follows:

   private void btnLogException_Click(      object sender, EventArgs e)   {      try      {         throw new Exception ("This is a sample exception");      }      catch (Exception ex)      {         bool rethrow = ExceptionPolicy.HandleException
?
Figure 3. Log Only Exception: When you inspect the Application Event Log after running the Log Only exception example, you'll see the logged information in the format specified by the configuration.
(ex, "Log Only Policy"); if (rethrow) { throw; } } }

The code in the catch block passes the exception object and the exception policy name (“Log Only Policy” in this case) to the the ExceptionPolicy.HandleException() method.

Run the application and press F5. The error is thrown and logged, but this time you won’t see a MessageBox; however, if you open Windows Event Viewer you will see that the application logged an entry to the Application Event Log. If you click on that entry you’ll see a dialog similar to the one shown in Figure 3.

Using the Exception Handling Block with WCF Services
WCF services are slightly different than desktop applications. When an exception occurs in a WCF service, the WCF service propagates that exception back to the caller. For a plain WCF service, you specify a fault contract that determines the exception information propagated back to the caller. By decorating the service operation with a fault contract attribute, you can specify that the operation will return a fault of a particular type.

The Exception Handling block shields a WCF service from disclosing information about its internal implementation when an exception occurs. To use the Exception Handling block with a WCF service, following this procedure:

  1. Using the Add Reference option, import the Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF.dll assembly to your WCF service project.
  2. Create a data contract that acts as a placeholder for storing details about the exception.
  3. Configure a WCF shielding policy in the section of the configuration file.
  4. Decorate the service interface with the [ExceptionShielding] attribute.
  5. Decorate the service operation with the [FaultContract] attribute, and supply the name of the data contract class created in step 2.

Here’s a detailed example. First, create a data contract class named WCFServiceFault with two properties: a string property named FaultMessage and a GUID property named FaultID.

   using System;   using System.Runtime.Serialization;   [DataContract]   public class WCFServiceFault   {      private string _faultMessage;      private Guid _faultID;         [DataMember]      public string FaultMessage      {         get { return _faultMessage; }         set { _faultMessage = value; }      }      [DataMember]      public Guid FaultID      {         get { return _faultID; }         set { _faultID = value; }      }   }

Next, add the WCF Exception Shielding policy as a child element of the element.

                                                                                    

In the configuration shown above, note that the default exception handling policy name is “WCF Exception Shielding.” By default, the Exception Handling block looks for this policy name at run time. As you can see from the section, the exception handler class named FaultContractExceptionHandler implements the WCF Exception Shielding policy by converting the exception to the FaultContract specified in the faultContractType attribute.

Using the section, you provide the information to map the exception details to the properties of the WCFServiceContract class. After adding the configuration settings, create a new WCF service named ProductService, and import the Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF namespace.

   using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF;

Then decorate the service interface and the service implementation classes with the exception handling-related attributes:

   using System.ServiceModel;   using System.Runtime.Serialization;   using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF;   [ServiceContract()]   [ExceptionShielding]   public interface IProductService   {      [OperationContract]      [FaultContract(typeof(WCFServiceFault))]      string GetProductName(int productID);       }      public class ProductService : IProductService   {      public string GetProductName(int productID)       {         return "Sample Product";      }      }

Note the use of the [ExceptionShielding] attribute that decorates the IProductService class and the [FaultContract] attribute that passes the WCFServiceFault class type as an argument right before the code invokes the GetProductName method.

That’s all that’s involved in shielding the exception information from the service side. On the client side, when an exception occurs in the service, you’ll want to receive a meaningful exception and let the user know what happened. Your code should catch a FaultException where T is the type of FaultContract used. Here’s some example client-side code:

   Try   {      // Call the exception shielding-enabled WCF service method   }   catch (FaultException exception)   {      WCFServiceFault fault = exception.Detail;      MessageBox.Show(fault.FaultMessage);      MessageBox.Show(fault.FaultID);   }

When the preceding code catches the exception, the Detail property returns the WCFServiceFault object, which contains the FaultID and FaultMessage values. The code displays those in a MessageBox for the user.

That accomplishes the goal of hiding implementation details from users by mapping WCF exceptions to a FaultContract type that you can catch as an exception in the client code.

You’ve seen some examples of how to use the Exception Handling block for logging, wrapping, replacing, and propagating exceptions in a standard Windows Forms application as well as how to use the Exception Handling block to shield WCF services from exposing sensitive information to clients. Despite the initial complexity of the configuration required to set up this generic exception handling, with a little practice, you’ll find Exception Handling block ideal for creating .NET applications that are flexible and easy to maintain.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

Recent Articles: