Exception Management

patterns & practices Developer Center

  • How to: Shield Exception Information with Fault Contracts
  • How to: Check the State of a Channel in WCF Proxy Client
  • How to: Avoid Faulting the Channels with Fault Contracts
  • How to: Create an Error Handler to Log Details of Faults for Auditing Purposes
  • How to: Handle Unhandled Exceptions in Downstream Services
  • How to: Throw an Exception with Complex Types or Data Contracts with a Fault Exception
  • How to: Handle Unknown Faults in a Service
  • How to: Implement a Data Contract to Propagate Exception Details for Debugging Purposes
  • How to: Implement Fault Contracts in Callback Functions

How to: Shield Exception Information with Fault Contracts

A fault contract details the set of exceptions that can be reported to the caller. You can specify the possible faults that can occur in your WCF service. This prevents exposing exception details beyond the defined set to your clients. Because a fault contract lists the types of errors that a WCF service can throw, it also allows your clients to distinguish between contracted faults and other possible errors.

Perform the following steps to shield exception information with fault contracts:

  1. Define a fault contract by applying the FaultContract attribute directly on a contract operation, and specifying the error detailing type to the method as follows:

    [ServiceContract]
    interface ICalculator
    {
       [OperationContract]
       [FaultContract(typeof(DivideByZeroException))]
       double Divide(double number1,double number2);
    }
    
  2. Implement the Divide operation that throws the fault and have it propagated to the client by throwing exactly the same detailing type listed in the fault contract.

    class MyService : ICalculator
    {
       public double Divide(double number1,double number2)
       {
          throw new FaultException<DivideByZeroException>(new DivideByZeroException());
       }
    }
    

Additional Resources

How to: Check the State of a Channel in WCF Proxy Client

You can check the state of a channel during proxy invocation by checking its value (proxy.State). This allows you to avoid throwing an exception on the proxy channel as a result of the channel being closed due to an unhandled exception on the service. The following code example shows you how to check the state of the channel.

try
      {
           ServiceClient proxy = new ServiceClient();
           proxy.ClientCredentials.UserName.UserName = "user";
           proxy.ClientCredentials.UserName.Password = "password";
           proxy.GetData(2);
           if (proxy.State = CommunicationState.Opened)
           {
               proxy.GetData("data");
           }
           proxy.Close();
      }
      catch (FaultException ex)
      {
          // handle the exception      
      }

How to: Avoid Faulting the Channels with Fault Contracts

When calling a WCF service, if the service throws any exceptions, the communication channel goes into the faulted state and you cannot use the proxy for any further calls. You can avoid this by throwing a FaultException in your service operations. The service operation that throws a FaultException must be decorated with one or more FaultContract attributes.

Perform the following steps to throw a FaultException:

  1. Define a fault contract by applying the FaultContract attribute directly on a contract operation and specifying the error detailing type to the method, as shown below:

    [ServiceContract]
    interface ICalculator
    {
       [OperationContract]
       [FaultContract(typeof(DivideByZeroException))]
       double Divide(double number1,double number2);
    }
    
  2. Implement the Divide operation that throws the fault and have it propagated to the client by throwing exactly the same detailing type listed in the fault contract:

    class MyService : ICalculator
    {
       public double Divide(double number1,double number2)
       {
          throw new FaultException<DivideByZeroException>(new DivideByZeroException());
       }
    }
    
  3. Handle the faults at the client side by catching the FaultException and any other communication exceptions that could occur when calling the service operations:

    try
    {
      proxy.Divide();
    }
    catch (FaultException<DivideByZeroException> ex)
    {
      // only if a fault contract of type DivideByZeroException was specified 
    }
    
    catch (FaultException ex)
    {
      // any other faults 
    }
    
    catch (CommunicationException ex)
    {
      // any communication errors? 
    }
    

Additional Resources

How to: Create an Error Handler to Log Details of Faults for Auditing Purposes

You can create an error handler to log fault details by implementing the IErrorHandler interface methods in your service. This allows you to log and suppress the exceptions, or to log and throw them as a FaultException. The following code sample shows the methods of the IErrorHandler interface.

public interface IErrorHandler 
{ 
        bool HandleError(Exception error, MessageFault fault); 
        void ProvideFault(Exception error, ref MessageFault fault, ref string faultAction); 
} 

To suppress the fault message, implement the HandleError method and return false. In this method, you can add your code for logging capabilities.

To raise a FaultException instead of suppressing the fault, implement the ProvideFault method to provide the MessageFault value. The following code shows a sample implementation of the ProvideFault method:

public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
  FaultException newEx = new FaultException();
  MessageFault msgFault = newEx.CreateMessageFault();
  fault = Message.CreateMessage(version, msgFault, newEx.Action);
}

Additional Resources

How to: Handle Unhandled Exceptions In Downstream Services

Use a global exception handler to catch unhandled exceptions and prevent them from being propagated to the client.

You can handle the unhandled exceptions in a WCF service by subscribing to the Faulted event of a service host object. By subscribing to this event, you can determine the cause of a failure and then perform the necessary actions to abort or restart the service.

The following code snippet shows how to subscribe to the Faulted event:

// hosting a WCF service 
ServiceHost customerServiceHost;
customerServiceHost = new ServiceHost(…);
…
// Subscribe to the Faulted event of the customerServiceHost object
customerServiceHost.Faulted += new EventHandler(faultHandler);
…
// FaultHandler method - invoked when customerServiceHost enters the Faulted state
void faultHandler(object sender, EventArgs e)
{     // log the reasons for the fault…
}

Additional Resources

How to: Throw an Exception with Complex Types or Data Contracts with a Fault Exception

The following steps show an example of how to throw an exception with a data contract that has a complex type:

  1. Define the DataContract type to pass the details of Simple Object Access Protocol (SOAP) faults as exceptions from a service back to a client:

    [DataContract]
    public class DatabaseFault
    {
    [DataMember]
    public string DbOperation;
    [DataMember]
    public string DbReason
    [DataMember]
    public string DbMessage;
    }
    
  2. Use the FaultContract attribute in the ListCustomers method to generate SOAP faults as follows:

    [ServiceContract]
    public interface ICustomerService
    {
    // Get the list of customers
    [FaultContract(typeof(DatabaseFault))]
    [OperationContract]
    List<string> ListCustomers();
    …
    }
    
  3. Create and populate the DatabaseFault object with the details of the exception in the service implementation class, and then throw a FaultException object with the DatabaseFault object details as follows:

    catch(Exception e)
    {    DatabaseFault df = new DatabaseFault();
    df.DbOperation = "ExecuteReader";
    df.DbReason = "Exception in querying the Northwind database.";
    df.DbMessage = e.Message;
    throw new FaultException<DatabaseFault>(df);
    }
    

Additional Resources

How to: Handle Unknown Faults in a Service

To handle unknown faults in a service, throw an instance of FaultException directly. Any FaultException<T> thrown by the service always reaches the client as a FaultException<T> or as FaultException. The FaultException<T> class is derived from the FaultException class.

throw new FaultException("Specify some reason");

Additional Resources

How to: Implement a Data Contract to Propagate Exception Details for Debugging Purposes

Perform the following steps to implement a data contract to propagate exception details for debugging purposes:

  1. Create a DataContract, with a member variable for storing the fault reason:

    [DataContract]
        public class MyDCFaultException
        {
            private string _reason;
    
            [DataMember]
            public string Reason
            {
                get { return _reason; }
                set { _reason = value; }
            }
        }
    
  2. Create a service contract, specifying a FaultContract with the above DataContract type for an operation:

    [ServiceContract()]
        public interface IService
        {
            [OperationContract]
            [FaultContract(typeof(MyDCFaultException))]
            string DoSomeComplexWork();
        }
    
  3. Implement the service operation. If any errors occur, send the exception details by throwing a FaultException of type MyDCFaultException as follows:

    public class Service : IService
      {    
    
        public string DoSomeComplexWork()
        {
         try
          {
                  // some complex operations
          }
          catch (Exception exp)
          {
            MyDCFaultException theFault = new MyDCFaultException();
            theFault.Reason = "Some Error " + exp.Message.ToString();
            throw new FaultException<MyDCFaultException>(theFault);
          }
            return "No Error";
    
       }
    
  4. Call the service operation from a client application. Get the original service exception reason by using the Detail.Reason property as follows:

      try
       {
        localhost.IService proxy = new localhost.ServiceClient();
        result = proxy.DoSomeComplexWork();
       }
    
      catch (FaultException<localhost.MyDCFaultException> ex)
       {
         result = "Exception: " + ex.Detail.Reason;
       }
    
       Console.WriteLine(result);
       Console.ReadLine();            
    

You can also send managed exception information to the clients by using the IncludeExceptionDetailInFaults property in the serviceDebug element of your service behavior as shown below. By default, its value is false; you can change it to true for debugging or problem diagnosis.

<system.serviceModel>
    <services>
        <service name="MyService"
                         behaviorConfiguration="MyServiceBehavior">
        </service>
    </services>
    <behaviors>
        <serviceBehaviors>
            <behavior name="MyServiceBehavior">
                <serviceDebug includeExceptionDetailInFaults="true"/>
            </behavior>
        </serviceBehaviors>
    </behaviors>
</system.serviceModel>

Additional Resources

How to: Implement Fault Contracts in Callback Functions

In duplex bindings, you need to implement the service with a callback contract specifying the interface so that the client can implement it. Use the CallbackContract attribute in the service contract to specify the type of callback contract that has the callback function.

The following code example shows a service that specifies a callback contract:

[ServiceContract(CallbackContract = typeof(IMyContractCallback))]
interface IMyContract
{
   [OperationContract]
   void DoSomething( );
}
interface IMyContractCallback
{
   [OperationContract]
   [FaultContract(typeof(InvalidOperationException))]
   void OnCallBack( );
}

Additional Resources