Defining and Specifying Faults

SOAP faults convey error condition information from a service to a client and, in the duplex case, from a client to a service in an interoperable way. This topic discusses when and how to define custom fault content and specify which operations can return them. For more information about how a service, or duplex client, can send those faults and how a client or service application handles these faults, see Sending and Receiving Faults. For an overview of error handling in Windows Communication Foundation (WCF) applications, see Specifying and Handling Faults in Contracts and Services.

Overview

Declared SOAP faults are those in which an operation has a System.ServiceModel.FaultContractAttribute that specifies a custom SOAP fault type. Undeclared SOAP faults are those that are not specified in the contract for an operation. This topic helps you identify those error conditions and create a fault contract for your service that clients can use to properly handle those error conditions when notified by custom SOAP faults. The basic tasks are, in order:

  1. Define the error conditions that a client of your service should know about.

  2. Define the custom content of the SOAP faults for those error conditions.

  3. Mark your operations so that the specific SOAP faults that they throw are exposed to clients in WSDL.

Defining Error Conditions That Clients Should Know About

SOAP faults are publicly described messages that carry fault information for a particular operation. Because they are described along with other operation messages in WSDL, clients know and, therefore, expect to handle such faults when invoking an operation. But because WCF services are written in managed code, deciding which error conditions in managed code are to be converted into faults and returned to the client provides you the opportunity to separate error conditions and bugs in your service from the formal error conversation you have with a client.

For example, the following code example shows an operation that takes two integers and returns another integer. Several exceptions can be thrown here, so when designing the fault contract, you must determine which error conditions are important for your client. In this case, the service should detect the System.DivideByZeroException exception.

[ServiceContract]  
public class CalculatorService  
{  
    [OperationContract]
    int Divide(int a, int b)  
    {  
      if (b==0) throw new Exception("Division by zero!");  
      return a/b;  
    }  
}  
<ServiceContract> _
Public Class CalculatorService
    <OperationContract> _
    Public Function Divide(a As Integer, b As Integer) As Integer
        If b = 0 Then Throw New DivideByZeroException("Division by zero!")
        Return a / b
    End Function
End Class

In the preceding example the operation can either return a custom SOAP fault that is specific to dividing by zero, a custom fault that is specific to math operations but that contains information specific to dividing by zero, multiple faults for several different error situations, or no SOAP fault at all.

Define the Content of Error Conditions

Once an error condition has been identified as one that can usefully return a custom SOAP fault, the next step is to define the contents of that fault and ensure that the content structure can be serialized. The code example in the preceding section shows an error specific to a Divide operation, but if there are other operations on the Calculator service, then a single custom SOAP fault can inform the client of all calculator error conditions, Divide included. The following code example shows the creation of a custom SOAP fault, MathFault, which can report errors made using all math operations, including Divide. While the class can specify an operation (the Operation property) and a value that describes the problem (the ProblemType property), the class and these properties must be serializable to be transferred to the client in a custom SOAP fault. Therefore, the System.Runtime.Serialization.DataContractAttribute and System.Runtime.Serialization.DataMemberAttribute attributes are used to make the type and its properties serializable and as interoperable as possible.

// Define a math fault data contract
[DataContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public class MathFault
{
    private string operation;
    private string problemType;

    [DataMember]
    public string Operation
    {
        get { return operation; }
        set { operation = value; }
    }

    [DataMember]
    public string ProblemType
    {
        get { return problemType; }
        set { problemType = value; }
    }
}
' Define a math fault data contract
<DataContract([Namespace]:="http://Microsoft.ServiceModel.Samples")> _
Public Class MathFault

    Private m_operation As String
    Private m_problemType As String

    <DataMember()> _
    Public Property Operation() As String

        Get

            Return m_operation

        End Get

        Set(ByVal value As String)

            m_operation = value

        End Set

    End Property

    <DataMember()> _
    Public Property ProblemType() As String

        Get

            Return m_problemType

        End Get

        Set(ByVal value As String)

            m_problemType = value

        End Set

    End Property

End Class

For more information about how to ensure your data is serializable, see Specifying Data Transfer in Service Contracts. For a list of the serialization support that System.Runtime.Serialization.DataContractSerializer provides, see Types Supported by the Data Contract Serializer.

Mark Operations to Establish the Fault Contract

Once a serializable data structure that is returned as part of a custom SOAP fault is defined, the last step is to mark your operation contract as throwing a SOAP fault of that type. To do this, use the System.ServiceModel.FaultContractAttribute attribute and pass the type of the custom data type that you have constructed. The following code example shows how to use the FaultContractAttribute attribute to specify that the Divide operation can return a SOAP fault of type MathFault. Other math-based operations can now also specify that they can return a MathFault.

[OperationContract]
[FaultContract(typeof(MathFault))]
int Divide(int n1, int n2);
<OperationContract()> _
<FaultContract(GetType(MathFault))> _
Function Divide(ByVal n1 As Integer, ByVal n2 As Integer) As Integer

An operation can specify that it returns more than one custom fault by marking that operation with more than one FaultContractAttribute attribute.

The next step, to implement the fault contract in your operation implementation, is described in the topic Sending and Receiving Faults.

SOAP, WSDL, and Interoperability Considerations

In some circumstances, especially when interoperating with other platforms, it may be important to control the way a fault appears in a SOAP message or the way it is described in the WSDL metadata.

The FaultContractAttribute attribute has a Name property that allows control of the WSDL fault element name that is generated in the metadata for that fault.

According to the SOAP standard, a fault can have an Action, a Code, and a Reason. The Action is controlled by the Action property. The Code property and Reason property are both properties of the System.ServiceModel.FaultException class, which is the parent class of the generic System.ServiceModel.FaultException<TDetail>. The Code property includes a SubCode member.

When accessing non-services that generate faults, certain limitations exist. WCF supports only faults with detail types that the schema describes and that are compatible with data contracts. For example, as mentioned above, WCF does not support faults that use XML attributes in their detail types, or faults with more than one top-level element in the detail section.

See also