Error

Catch All WCF Errors

Want to log all uncaught errors in a WCF service? Want to return a nicely formatted fault exception too?

IErrorHandler can help.

I like using this interface as you can apply it to an entire WCF Service with just a few lines of code, making it easy to use against numerous WCF services ensuring that your error handling is reliable. It allows you to log your errors in a consistent manner and also do any bespoke cleaning up of resources that you might want to do. On top of this, your implementation of the ErrorHandler can (and should) exist totally outside of your WCF service, allowing a good separation of concerns

This interface exposes two methods:

1. provide fault: This is where you can provide what fault gets sent to the client. By default, sometimes the error gets wrapped up in a fault exception and sent to the client. Sometimes not. Here is where you can wrap up the exception any way you like and return it to the client in a fault exception.

2. handle error: This is where you prove code to handle the error and commonly where you will log the error, raise system alerts, etc.

For MSDN’s description, see here

Let’s Create our class

public class MyErrorHandler : IErrorHandler
{
		private readonly ILog _logger;

		public ErrorHandler()
			:this(LogManager.GetLogger("myassembly"))
		{}

		public MyErrorHandler(ILog logger)
		{
			_logger = logger;
		}
}

Nothing too exciting here – we’re injecting a logging object, or creating one if not provided. We need to implement that interface though.

Let’s provide a fault.

public void ProvideFault(Exception ex, MessageVersion version, ref Message fault)
{
	if (ex is FaultException)
	{
		return;	//WCF will handle this
	}

	var messageFault = MessageFault.CreateFault(new FaultCode("Service"), new FaultReason(ex.Message), ex, new NetDataContractSerializer());
	fault = Message.CreateMessage(version, messageFault, null);
}

In this example I want to make sure that the client receives the error in the fault every time. If the exception is already of type FaultException, then nothing need be done.
So here we are creating a new Message, which contains the exception message. If we didn’t want the client to know the specifics of the fault we could just create a generic message here instead of the exception message.

Let’s handle that error

public bool HandleError(Exception ex)
{
	_logger.Error(ex.Message, ex);

	if (ex is FaultException)
	{
		return false;	//WCF will handle this
	}

	return true;
}

The first line logs the error. Then as you probably noticed this method needs to return a bool. This is so that the dispatcher knows if the error was handled or not. You want to return false in the event the error is a FaultException, as WCF will automatically handle this. Otherwise we need to tell it that we’ve handled it (true).

Wiring it into the WCF service

There are a few ways to achieve this. My preferred method is to take the least painful way and make our ErrorHandler class implement IContractBehaviour and apply it as an attribute to the service’s DataContract. Taking a step back what we need to do is add our ErrorHandler class to the collection of ChannelDispatchers.ErrorHandlers, so our WCF service will use our custom ErrorHandler.

This is how we do it.  First add the interface to our class.

public class MyErrorHandler : IErrorHandler, IContractBehavior
{
...

Now implement the interface, adding our implementation of IErrorHandler to the collection of ErrorHandlers.

public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
	dispatchRuntime.ChannelDispatcher.ErrorHandlers.Add(this);
}

public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{}

public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{}

public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{}

Now the final part of the wiring up is to make MyErrorhandler an attribute

public class MyErrorHandler : Attribute, IErrorHandler, IContractBehavior

and apply it to our WCF Service interface

 [ServiceContract]
 [MyErrorHandler]
 public interface IMyService
    {
      ... my interface methods

That’s it. There is an even cleaner way of wiring up the MyErrorHandler class – detail in my next blog to come.

Advertisements