Fault Contract to Propagate Exception

When Windows Communication Foundation needs to propagate errors between servers and clients, it needs to handle propagation in distributed manner.  This implies the error handling mechanism must be done in language agnostic fashion.  Dot Net exception is language specific error handling mechanism, and it is inadequate to address distributed nature of error handling mechanism.

Fault contracts is the answer to handle exception within interoperability context.  Fault contract makes the distinction from Dot Net exception.

Minimal Code to Declare Fault Contract

All operation contracts throw untyped fault contract.  You may declare FaultContractAttribute to declare typed fault contract.

 1 namespace FaultDemoLibrary
 2 {
 3   using System.Runtime.Serialization;
 4   using System.ServiceModel;
 5 
 6   [ServiceContract]
 7   public interface IService
 8   {
 9     /* Note 1 */ [OperationContract]
10     void ThrowUntypedFaultOperation();
11 
12     [OperationContract]
13     /* Note 2 */
14     [FaultContract(typeof(DemoFault))]
15     [FaultContract(typeof(AnotherDemoFault))]
16     void ThrowDeclaredFaultOperation(int code);
17   }
18 
19   [DataContract]
20   public class DemoFault { //... }
21 
22   [DataContract]
23   public class AnotherDemoFault { //... }
24 }
  • Note 1.  Operation without FaultContractAttribute uses untyped fault contract.
  • Note 2.  Two typed fault are declared in this operation - DemoFault and AnotherDemoFault.  For typed fault contract, the type must be based on DataContract or Serializable type.  Remember serialization is required to distribute message.

Additionally, two expected exceptions can be thrown by service operations.  Thus, don’t rethrow them to fault contract unless the exceptions are not originated by WCF itself.

  • TimeoutException
  • CommunicationException

Catching Fault Contracts from Clients

  • Note 1.  WCF clients should catch fault contracts, expressed as FaultExcpetion and like, in this order.
    • Typed FaultExcpetion.
    • Untyped FaultException
    • TimoutExcpetion
    • CommunicationException
 1 namespace FaultDemoClient
 2 {
 3   using System;
 4   using System.ServiceModel;
 5   using FaultDemoLibrary;
 6 
 7   internal class ExampleClient
 8   {
 9     public void CallServiceOperation(BasicHttpBinding binding, string url)
10     {
11       using (var factory = new ChannelFactory<IService>(binding, url))
12       {
13         try
14         {
15           // Call service operation
16           var proxy = factory.CreateChannel();
17           proxy.ThrowUntypedFaultOperation();
18           proxy.ThrowDeclaredFaultOperation(1);
19         }
20         /* Note 1 */
21         catch (FaultException<DemoFault> ex) {}
22         catch (FaultException<AnotherDemoFault> ex) {}
23         catch (FaultException ex) {}
24         catch (TimeoutException ex) {}
25         catch (CommunicationException ex) {}
26       }
27     }
28   }
29 }

Controlling Error Details with IncludeExceptionDetailInFaults

When a WCF host restricts error propagation to client, clients receive the following error message - Error: The server was unable to process the request due to an internal error.

To allow error propagation for debugging purpose, set ServiceBehaviorAttribute.IncludeExceptionDetailInFaults Property value to true.

Important.  Read API above regarding security risk.

Number of Ways to Set IncludeExceptionDetailInFaults Property

By Configuration File - the Preferred Method

All service contract fault contracts are affected.

1 <serviceBehaviors>
2   <behavior name="metadataAndDebugEnabled">
3     <serviceDebug includeExceptionDetailInFaults="true" />
4   </behavior>
5 </serviceBehaviors>

Programmatic Approach

1 var host = new ServiceHost(typeof(MyService));
2 var debuggingBehavior =
3   host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
4 debuggingBehavior.IncludeExceptionDetailInFaults = true;
5 
6 host.Open();

Declarative Approach - Per Contract Only

This approach specifies the value on per service contract basis.

1 [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
2 class MyService : IMyService
3 {
4   //...
5 }

Further Study