Return custom exception data through FaultContract

In an XML Web Service and WCF service, the server side will return any unhandled exception as SoapFault in the returned message. For WCF service operations, exceptions are returned to the client through two steps:

  • Map exception conditions to custom SOAP faults
  • Services and client send and receive SOAP faults as exceptions

By default, WCF will return the simple error message or complete exception information (including Callstack) as the Fault content. However, sometimes we want to encapsulate the raw exception information or return some user-friendly error to the client side. To support this kind of customized exception-information format, WCF has provided the FaultContract and FaultException features. FaultException is a new exception type that uses Generic to help WCF service encapsulate various kinds of custom error data objects in a unified way. FaultContract is used to formally specify the type of FaultException that will be returned from the target WCF service operation, so that the client consumers can properly handle and parse it.

How to do it...

  1. First, create the custom error type that will be returned to the service client as exception information. The custom error type is defined as a standard DataContract type.
  2. Then, apply the custom error type to the service operation (which will return this custom error type) through a FaultContractAttribute.
  3. The following code shows a sample custom error type and the service operation that applies it:
      [DataContract]
        public class UserFriendlyError
        {
            [DataMember]
            public string Message
            { get;set; }
        }
    
    [ServiceContract]
        public interface ICalcService
        {
            [OperationContract]
            int Divide(int lv, int rv);
    
            [OperationContract]
     [FaultContract(typeof(UserFriendlyError))]
            int DivideWithCustomException(int lv, int rv);
    }
  4. Finally, we need to add our exception handling code in the service operation's implementation and return the custom error type through the FaultException<T> type (see DivideWithCustomException method shown as follows):
    public int Divide(int lv, int rv)
    {
        if (rv == 0) throw new Exception("Divided by Zero is not allowed!");
        return lv / rv;
            }
    
    public int DivideWithCustomException(int lv, int rv)
    {
     if (rv == 0) throw new FaultException<UserFriendlyError>(new UserFriendlyError() { Message = "Divided by Zero is not allowed!" }
     );
        return lv / rv; 
    }

How it works...

The FaultContractAttribute applied on the service operation will make the runtime generate corresponding metadata entries in the WSDL document (as shown in the next screenshot). Thus, the generated client proxy knows how to handle this custom error type.

How it works...

When invoking the operation, we can add code to handle the specific FaultException and get user-friendly error information from the Exception.Detail property.

try
{
     //call the operation with invalid parameter
}
catch (FaultException<UserFriendlyError> fex)
{
     Console.WriteLine("Error: {0}", fex.Detail.Message);
}

If we use Fiddler or message logging to inspect the underlying SOAP message, we can also find the custom error data in XML-serialized format:

How it works...

There's more...

Since the custom error type used by FaultContract supports any valid DataContract type, we can define various kinds of custom exception data content (from simple primitive types to complex nested classes).

See also

  • Generating DataContract from XML Schema
  • Capturing a WCF request/response message via Fiddler tool in Chapter 12
  • Complete source code for this recipe can be found in the \Chapter 1\recipe7\ folder