Fault Contract Exception Handler

Topics: Exception Handling Application Block
Apr 30, 2014 at 11:23 PM
Edited Apr 30, 2014 at 11:24 PM
I am trying to use the Fault Contract Exception Handler in Enterprise Library 6.0. This is how the I am testing the code and configuration:
  1. A windows forms client calls a WCF service method.
  2. The WCF service operation throws a custom exception of the type System.Exception with a hard coded message.
  3. The catch block in the service operation catches the exception calls enterprise library to handle the exception.
The exception handler are set up like this:
The handler is setup for all exceptions. Post handling action is 'Throw New Exception'.

First handler is Logging Exception Handler.
Second handler is Fault Contract Exception Handler with a message specified in the configuration file.

I was expecting the original exception to be logged and then the Fault Exception with the specified fault contract to be thrown back to the client.

The code works perfeclty fine with one unexpected behavior. Both original exception and fault exception are logged and then the Fault Exception is thrown to the client. If the logging habdler is before the fault contract handler, the fault contract exception should not be logged. Correct? Please help me figure out why the fault contract exception is logged. I do not want to log the Fault Exception.

If I remove the Logging handler, no logging takes place and the fault exception is thrown back to the client.

Thanks for your help.

The configuration is copied and pasted below:

<exceptionPolicies>
  <add name="FSET Web Service Policy">
    <exceptionTypes>
      <add name="All Exceptions" type="System.Exception, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
        postHandlingAction="ThrowNewException">
        <exceptionHandlers>
          <add name="Logging Exception Handler" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.LoggingExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
            logCategory="General" eventId="100" severity="Error" title="Enterprise Library Exception Handling"
            formatterType="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.TextExceptionFormatter, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling"
            priority="0" />
          <add type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF.FaultContractExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
            exceptionMessage="An internal error has occured and has been logged. Contact system administrator."
            faultContractType="Edd.Camp.ExceptionHandlingLoggingProtoype.WCF.DataContracts.FsetServiceFault, Edd.Camp.ExceptionHandlingLoggingProtoype.WCF.DataContracts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
            name="Fault Contract Exception Handler">
            <mappings>
              <add source="Message" name="ErrorMessage" />
            </mappings>
          </add>
        </exceptionHandlers>
      </add>
    </exceptionTypes>
  </add>
</exceptionPolicies>
May 1, 2014 at 12:56 PM
For exception shielding you would usually not "manually" catch exceptions but instead use the ExceptionShielding Attribute applied to the service:
    [ExceptionShielding]
    public class Service1 : IService1
    {
        public string GetData(int value)
        {
            throw new Exception("Oops!");
            return string.Format("You entered: {0}", value);
        }

    }
Now all exceptions will be handled using the policy called "WCF Exception Shielding".

Here is the config:
<?xml version="1.0"?>
<configuration>

  <configSections>
    <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
    <section name="exceptionHandling" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
  </configSections>
  <loggingConfiguration name="" tracingEnabled="true" defaultCategory="General">
    <listeners>
      <add name="Flat File Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        fileName="trace.log" />
    </listeners>
    <categorySources>
      <add switchValue="All" name="General">
        <listeners>
          <add name="Flat File Trace Listener" />
        </listeners>
      </add>
    </categorySources>
    <specialSources>
      <allEvents switchValue="All" name="All Events" />
      <notProcessed switchValue="All" name="Unprocessed Category" />
      <errors switchValue="All" name="Logging Errors &amp; Warnings" />
    </specialSources>
  </loggingConfiguration>
  <exceptionHandling>
    <exceptionPolicies>
      <add name="WCF Exception Shielding">
        <exceptionTypes>
          <add name="All Exceptions" type="System.Exception, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
            postHandlingAction="ThrowNewException">
            <exceptionHandlers>
              <add name="Logging Exception Handler" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.LoggingExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                logCategory="General" eventId="100" severity="Error" title="Enterprise Library Exception Handling"
                formatterType="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.TextExceptionFormatter, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling"
                priority="0" />
              <add type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF.FaultContractExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                faultContractType="WcfService1.MyServiceFault, WcfService1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
                name="Fault Contract Exception Handler">
                <mappings>
                  <add source="Message" name="MyMessage" />
                </mappings>
              </add>
            </exceptionHandlers>
          </add>
        </exceptionTypes>
      </add>
    </exceptionPolicies>
  </exceptionHandling>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5"/>
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
        <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>    
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <directoryBrowse enabled="true"/>
  </system.webServer>

</configuration>
Also you will need to bootstrap the blocks. I used Application_Start:
    public class Global : System.Web.HttpApplication
    {
        protected void Application_Start(object sender, EventArgs e)
        {
            var configSource = ConfigurationSourceFactory.Create();
            Logger.SetLogWriter(new LogWriterFactory(configSource).Create());
            ExceptionPolicy.SetExceptionManager(new ExceptionPolicyFactory(configSource).CreateManager());
        }
    }
~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to