WCF Exception Handling with Exception Handling Application Block Integration - Guy Burstein's Blog

Guy Burstein's Blog

Developer Evangelist @ Microsoft

News

Guy Burstein The Bu

Disclaimer
Postings are provided 'As Is' with no warranties and confer no rights.

Guy Burstein LinkedIn Profile

WCF Exception Handling with Exception Handling Application Block Integration

WCF Exception Handling with Exception Handling Application Block Integration

This post is one of a post series about WCF Integration in Enterprise Library 3.0. Specifically, this post is the first post I am talking about the integration between Exception Handling Application Block and Windows Communication Foundation (WCF). This post has a brief overview about the Exception Handling Application Block (EAB) and the WCF Fault Handling. Then, this post explains how to use the EAB integration with WCF.

Exception Handling Application Block

If you're familiar with the Exception Handling Application Block, you can skip to the next section. If you're not, stay around. To simply put it, the EAB works with exception handling policies. You configure a exception policy in the configuration file, and add one or more exception handlers to it. For example, the following configuration snippet configures a policy called "Server Policy" that replaces a Security Exceptions with Application Exceptions, and wraps a DB Concurrency Exception with a custom Exception Type.

<exceptionPolicies>

  <add name="Server Policy">

    <exceptionTypes>

      <add name="SecurityException"

           type="System.Security.SecurityException 

           postHandlingAction="ThrowNewException">

        <exceptionHandlers>

          <add name="Replace Handler"

               type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ReplaceHandler"

               exceptionMessage="Replaced: User is not authorized to perform the requested action."

               replaceExceptionType="System.ApplicationException, mscorlib" />

        </exceptionHandlers>

      </add>

      <add name="DBConcurrencyException"

           type="System.Data.DBConcurrencyException, System.Data"

           postHandlingAction="ThrowNewException">

        <exceptionHandlers>

          <add name="Wrap Handler"

               type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WrapHandler"

               exceptionMessage="Wrapped Exception: An error occurred while attempting to access the DB."

               wrapExceptionType="MyApplicationException, MyApplication.Excecptions" />

        </exceptionHandlers>

      </add>

    </exceptionTypes>

  </add>

</exceptionPolicies>

Then, on order to handle an exception when caught, we use the following code:

try

{

    // Do some operation that may cause an exception

}

catch

{

    // Use the EAB to handle the exceptions according to the configuration

    if ( ExceptionPolicy.HandleException(ex, "Server Policy") ) throw;

}

WCF and Exceptions

WCF Exception Handling These is a lot to say about what happens when an exception occurs in a WCF Service Operation. To make a long story short, I'll say that the exception is not thrown back to the client and the channel becomes in Faulted state. The idea behind this design is that you don't want to reveal any information about the error that has occurs because it can contain information you don't want to share. For example, if you expose a Web Service to the Internet for other organizations to consume, you don't want them to know that you cannot insert a new record to table "tblUsers" because a user with name "Guy" already exists.

If you still want to return excecptions back to the client (recommended only during development time), you can add a service behavior: 

<serviceBehaviors>

  <behavior name="Debug">

    <serviceDebug includeExceptionDetailInFaults="true" />

  </behavior>

</serviceBehaviors>

Note that this configuration is used only for unhandeled exceptions. If you are using a FaultContract to specify what type of faults your service might return, this setting will not change a thing about it.

Exception Handling Application Block Integration with WCF

In this post, I will not get into details about how the integration works, and I will focus on the things you should do or configure in order to benefit from this integration.

First, you have to create a Data Contract that will contain the details about the error that has occurred. For example:

[DataContract]

public class ServiceFault

{

    private string message;

    private Guid id;

 

    [DataMember]

    public string MessageText

    {

        get { return message; }

        set { message = value; }

    }

 

    [DataMember]

    public Guid Id

    {

        get { return id; }

        set { id = value; }

    }

}

Second, you have to create a WCF shielding policy in the exception handling policies section in the configuration file, as displayed in this configuration snippet.

<exceptionHandling>

  <exceptionPolicies>

    <add name="WCF Exception Shielding">

      <exceptionTypes>

        <add type="System.InvalidOperationException, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" postHandlingAction="ThrowNewException" name="InvalidOperation">

          <exceptionHandlers>

            <add           type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF.FaultContractExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF"

              name="DefaultFaultContract Handler"

              faultContractType="Bursteg.Samples.WCFIntegration.ServiceContracts.ServiceFault, Bursteg.Samples.WCFIntegration.ServiceContracts">

              <mappings>

                <add name="Id" source="{Guid}"/>

                <add name="MessageText" source="{Message}"/>

              </mappings>

            </add>

          </exceptionHandlers>

        </add>

      </exceptionTypes>

    </add>

  </exceptionPolicies>

</exceptionHandling>

There are few things that you should notice in the above snippet:

1. The default name of the exception handling policy is WCF Exception Shielding. The exception handling app. block will look for this name if you don't tell it otherwise (more details later).

2. Make sure that the PostHandlingAction of the policy is ThrowNewException. This means that the exception with the FaultContract in it will be thrown after the handling is done.

3. The Exception handler called DefaultFaultContract  Handler is an Exception Handler of type FaultContractExceptionHandler (more details on the next post) which converts the handled exception (this time it's System.InvalidOperationException) to the FaultContract specified in the faultContractType attribute.

4. What this handler does in order to convert an exception to the configured fault contact, is simply mapping of properties according to the <mappings> list above. In this case the property MessageText in the ServiceFault class will get the value in the Message property of the exception. Notice that the Id property of the ServiceFault is mapped to the source {Guid}. This means that the Id property will have the Handling Instance Id property of the exceptions that is automatically created by the Exception Handling Application Block.

Third, you have to add the exception shielding into the service contract or the service class. This is done by the [ExceptionShielding] attribute.

[ServiceContract]

[ExceptionShielding]

public interface IOrdersService

{

    ...

}

If you changed the name of the policy that the exception shielding is using from WCF Exception Shielding, or you have many services and each one has its own specific policy, you should pass the name of the policy to this attribute:

[ServiceContract]

[ExceptionShielding("Policy Name")]

public interface IOrdersService

{

    ...

}

As I mentioned earlier, the FaultContractExceptionHandler converts the exception to a Fault Contract. This means that you have to specify the FaultContract to your service contract in order for receiving it in the client side:

[ServiceContract]

[ExceptionShielding]

public interface IOrdersService

{

    [OperationContract]

    [FaultContract(typeof(ServiceFault))]

    int CreateOrder(string currency, double amount);

 }

One thing you should note is that if you used the <serviceDebug> option and set the includeExceptionDetailInFault to true, the exception shielding will not work. So be sure to turn this option off.

Now, in order to receive this meaningful exception in the client, you should catch a FaultException<T> where T is the FaultContract use used.

try

{

    // Call the service method that has a fault contract on it

}

catch (FaultException<ServiceFault> ex)

{

    ServiceFault fault = ex.Detail;

    Console.WriteLine(fault.MessageText);

    Console.WriteLine(fault.Id);

}

You can download a sample project that shows this integration.

Enjoy!

Comments

No Comments