WCF exception handling using IErrorHandler

p0lAris picture p0lAris · Jul 31, 2013 · Viewed 16.6k times · Source

I am basically implementing the IErrorHandler interface to catch all kinds of exceptions from the WCF service and sending it to the client by implementing the ProvideFault method.

I am facing one critical issue however. All of the exceptions are sent to the client as a FaultException but this disables the client to handle specific exceptions that he may have defined in the service.

Consider: SomeException that has been defined and thrown in one of the OperationContract implementations. When the exception is thrown, its converted to a fault using the following code:

var faultException = new FaultException(error.Message);
MessageFault messageFault = faultException.CreateMessageFault();
fault = Message.CreateMessage(version, messageFault, faultException.Action);

This does send the error as a string, but the client has to catch a general exception like:

try{...}
catch(Exception e){...}

and not:

try{...}
catch(SomeException e){...}

Not only custom exceptions like SomeException, but system exceptions like InvalidOperationException cannot be caught using the above process.

Any ideas as to how to implement this behavior?

Answer

Vyacheslav Volkov picture Vyacheslav Volkov · Jul 31, 2013

In WCF desirable to use special exceptions described as contracts, because your client may not be .NET application which has information about standard .NET exceptions. For do this you can define the FaultContract in the your service and then use the FaultException class.

SERVER SIDE

[ServiceContract]
public interface ISampleService
{
    [OperationContract]
    [FaultContractAttribute(typeof(MyFaultMessage))]
    string SampleMethod(string msg);
}

[DataContract]
public class MyFaultMessage
{
    public MyFaultMessage(string message)
    {
        Message = message;
    }

    [DataMember]
    public string Message { get; set; }
}

class SampleService : ISampleService
{
    public string SampleMethod(string msg)
    {
        throw new FaultException<MyFaultMessage>(new MyFaultMessage("An error occurred."));
    }        
}

In addition, you can specify in the configuration file that the server returns exception details in it's FaultExceptions, but this is not recommended in a production application:

<serviceBehaviors>
   <behavior>
   <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
      <serviceDebug includeExceptionDetailInFaults="true"/>
   </behavior>
</serviceBehaviors>

After that, you can rewrite your method for handling exceptions:

var faultException = error as FaultException;
if (faultException == null)
{
    //If includeExceptionDetailInFaults = true, the fault exception with details will created by WCF.
    return;
}
MessageFault messageFault = faultException.CreateMessageFault();
fault = Message.CreateMessage(version, messageFault, faultException.Action);

CLIENT:

try
{
    _client.SampleMethod();
}
catch (FaultException<MyFaultMessage> e)
{
    //Handle            
}
catch (FaultException<ExceptionDetail> exception)
{
    //Getting original exception detail if includeExceptionDetailInFaults = true
    ExceptionDetail exceptionDetail = exception.Detail;
}