Wednesday, February 8, 2012

Generic Error Handling in WCF REST

It is very obvious that we will not have the luxury of throwing the service exceptions when we create web service wrappers to the business processing logic. But it is not end of the world. WCF provides IErrorHandler interface which allows us to handle all the exceptions that are generated from the layers below in generic fashion. For WCF this is OK, but what to do for WCF REST? Don't worry, the same interface can be enhanced to support the error handling functionality for WCF REST services as well. Below is the sample implementation of generic error handling in WCF REST services;

1) Implement the IErrorHandler interface

public class BSErrorHandler : IErrorHandler
{
public bool HandleError(Exception error)
{
return true;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
//This condition is needed to skip handling the WebFaultException
//since it is already handled in the layers below  (I have used WebFaultException<string>
//In case you use different type, add the condition for that)
if (!(error is System.ServiceModel.Web.WebFaultException))
{
//I have used XML type; so why I am using DataContractSerializer
//If you want to use JSON type, use DataContractJSONSerializer
fault = Message.CreateMessage(version,string.Empty, string.Format("Error: {0}", error.Message), new DataContractSerializer(typeof(string)));
fault.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Xml));
//Below code sets the response status to OK (200) so that client
//knows this is a valid response and handle it accordingly
HttpResponseMessageProperty hrp = new HttpResponseMessageProperty();
hrp.StatusCode = System.Net.HttpStatusCode.OK;
fault.Properties[HttpResponseMessageProperty.Name] = hrp;
}
}
}

2) Inject this error handler in the Channel Dispatcher as shown below;

public class CustomMessageBehavior : IEndpointBehavior

{
#region IEndpointBehavior Members
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
BSErrorHandler err = new BSErrorHandler();
endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(err);
}
public void Validate(ServiceEndpoint endpoint)
{
}
#endregion
}

3) Configure the dispatcher in the Web.Config

Job done!!