Whose fault is it?

Posted on December 26, 2010 by

0


In this post I’m going to explain what is the SOAP Fault, and how it should be handled.

There are 3 types of SOAP messages:

  1. Request
  2. Reply
  3. Fault

when the client receives a fault message, it  indicates  that an error occurred on the server side which WCF translated to the client as a fault. It is important to mention that faults are returned only on a two-way channel, which is the default channel behavior  (unless you explicitly define the operation as OneWay)

The SOAP Fault contains the following information:

  1. FaultCode – A code which identifies the fault
  2. FaultString – Readable explanation of the fault
  3. FaultActor – Who caused the fault
  4. Detail – Specific application error information

The basic idea of returning fault messages to the client instead of the original exception thrown by the server is because the server side does not want to expose unnecessary information to the client. Exposing such an information might be considered as a security violation, as we expose the server’s internal behavior.

What actually happens is that when the server side throws an exception from a WCF operation,  WCF runtime catches the exception and translate it to a corresponding  fault message.

How WCF creates the fault message?

To answer this question, we will take the following WCF contract as a reference:

   [ServiceContract]
    public interface ICalculator
    {
        [FaultContract(typeof(DivideByZeroException))]
        [OperationContract]
        string Divide(int x, int y);
    }

In the sample interface, we used the FaultContract attribute to indicate which kind of exceptions the developer expects the server to throw. (see msdn article – http://msdn.microsoft.com/en-us/library/cc304769.aspx)  This way the client knows what error cases it should handle.

When WCF creates the fault it compares the thrown exception to the list of exception defined by the FaultContract attribute on the operation.

The client will receive one of the following:

  1. FaultException<Detail>
  2. FaultException

FaultException<Detail> will be received on the client if one the following occurred:

1. The server threw FaultException<TDetail> where TDetail is defined on the operation with the FaultContract attribute. In our example, it means that the server threw FaultException<DivideByZeroException> and this is what the client will receive.

General Fault exception will be received on the client if one the following occurred:

1. The server threw FaultException<TDetail> where TDetail is NOT defined as a FaultContract exception on the operation (for example, the server threw FaultException<InvalidOperationException>)

2. When throwing exceptions not wrapped as FaultException from the server side.

In both cases, WCF runtime will catch the thrown exceptions and will translate them to a non-generic fault message (System.ServiceModel.FaultException) which will be sent to the client. The FaultException will contain the following message “The server was unable to process the request due to an internal error”.

There is a list of exceptions defined as fatal internally by WCF. For these exceptions the above behavior does not apply.

The FaultException behavior describes in this blog is very useful for servers exposed to external clients. In this scenario security is very important and is maintained by the Fault obfuscation. When both the client and server are internal in your system, the fault behavior might be considered redundant as we no longer need the security aspect.

In the next post I’m going to explain a trick we did, that enabled the client to catch the real exceptions thrown by the server instead of FaultException. We used this trick only in cases where both the client and the server were internal in our system, and we felt it is more natural that the client will catch the original exceptions, instead of trying to handle vague faults caused by unknown errors.

Useful links:

http://msdn.microsoft.com/en-us/library/cc304859.aspx

Advertisements
Posted in: Error Handling