Handling Fault Contracts

April 15, 2008 at 1:35 pm | Posted in WCF | 1 Comment

Today I had an issue with catching Fault Contracts thrown from my WCF service. Every FaultException type raised by the service (excluding Communication Exceptions) were caught by the client as a FaultException instead of the expected FaultException<T>.

The issue was that I defined the FaultContractAttribute(type) on the operations in the Service Implementation class instead of on the Service Contract’s (Interface class) operations.

A service should always handle/shield exceptions and throw them as either a FaultException or a FaultException<T>. These types will not cause the channel to be faulted. I recommend defining Fault Contracts to convey information about the problem to client applications, and DO NOT provide the internal exception such as service stack traces. I’ll blog a post in the future on my recommendations service exception shielding patterns.

To catch Fault Contract types on the client, make sure that each Fault Contract type you require for that service operation, ensure that the FaultContractAttribute(Type) is specified.

Service code

Error Handler

The following code is implemented in the IErrorHandler class and is based on Rory’s post on Implementing IErrorHandler . In this example, all exceptions in my WCF service are changed to FaultException<ServiceFault>.

public void ProvideFault(Exception error,
                         MessageVersion version,
                         ref Message fault)
{
    // Return a 'ServiceFault' Fault Contract
    ServiceFault faultDetail = new ServiceFault("An error occured");

    // Construct FaultException with Fault Contract and FaultReason
    FaultException<ServiceFault> faultException = 
        new FaultException<ServiceFault>(faultDetail, 
        new FaultReason("FaultReasonText"));

    // Construct MessageFault to return.
    MessageFault messageFault = faultException.CreateMessageFault();

    fault = Message.CreateMessage(version, 
        messageFault, 
        faultException.Action);
}

Service Contract

Now this is where I went wrong. I did not decorate my service contract with the FaultContractAttribute. This attribute accepts a Type parameter which should be the type of the Fault Contract.

namespace DJ.Wcf.Demo.ServiceContracts

{

    [ServiceContract(Name = “DJ.Wcf.Demo.DemoService”, Namespace = “DJ.Wcf.Demo”)]

    public interface IDemoService

    {

        [OperationContract]

        [FaultContract(typeof(ServiceFault))]

        DemoData GetDemoData(Int32 demoId);

    }

}

Service Fault Contract code

Here is a defined Fault Contract used by the service and client. Being a Data Contract, it could contain a collection of error messages e.g. a collection of validation error messages for a set of fields that were incorrectly set on the service operation.

using System;
using System.Runtime.Serialization;

namespace Wcf.Demo.ServiceContracts
{
    [DataContract]
    public class ServiceFault
    {
        public ServiceFault(String message)
        {
            Message = message;
        }

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

Client code

The service calling code below shows several catch statements. When the service passes back a ServiceFault, it will be caught in: catch (FaultException<ServiceFault>. All other FaultException and FaultException<T> types will be handled by: catch (FaultException fault) block.

Unhandled service exceptions will be raised and caught in:  catch (CommunicationException cex) which will cause the WCF channel to fault, thus forcing the client to create a new channel.

try
{
    using (ChannelFactory<IDemoService> channel = 
        new ChannelFactory<IDemoService>("DemoService"))
    {
        IDemoService service = channel.CreateChannel();
        channel.Open();

        return service.GetPerson(42);
    }
}
catch (FaultException<ServiceFault> serviceFault)
{
    MessageBox.Show(serviceFault.Message);
}
catch (FaultException fault)
{
    MessageBox.Show("Unknown Service Fault");
}
catch (TimeoutException tex)
{
    MessageBox.Show("Service call timed out. Please retry.");
}
catch (CommunicationException cex)
{
    MessageBox.Show("Unknown Communications exception occured.");
}

Advertisements

1 Comment »

RSS feed for comments on this post. TrackBack URI

  1. […] 2008 Release is available on MSDNAmbrose – Creating Software is Not Like BuildingDave Jansen – Handling Fault ContractsKirk Allen Evans – Calling Web Services via AJAX – Part […]


Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.
Entries and comments feeds.

%d bloggers like this: