18 July 2013

WCF and the Try-Catch-Abort Pattern

Proxy Classes are used to talk to Windows Communication Foundation (WCF) Services.
A communication channel is open to the WCF Service that must be closed after the calls to the service.
The proper way to close the communication channel is very important.
The WCF proxy is usually generated using Visual Studio or the svcutil tool.
The generated proxy inherits from a base class System.ServiceModel.ClientBase that implements the IDisposable interface.

The service can be called in a using block that automatically calls the Dispose() method.

using (MyService client = new MyService())
{
...
} // Dispose is called here
Dispose() calls the proxy close() method, that sends a message from the client to the service indicating that the connection session is no longer needed.
A problem can arise with this approach if there is an exception when calling the close() method. This is why the using approach is not recommended when calling WCF methods.

If the communication channel is in a faulted state Abort() should be called and not close();
The recommended approach is the Try-Catch-Abort Pattern.
This is a simple pattern where a try...catch block is used to call the service and in the catch of an exception the connection is aborted or closed.

The recomendation by Microsoft in MSDN is:
 
try
{
    ...
    client.Close();
}
catch (CommunicationException e)
{
    ...
    client.Abort();
}
catch (TimeoutException e)
{
    ...
    client.Abort();
}
catch (Exception e)
{
    ...
    client.Abort();
    throw;
}

A generic class for creating and initializing WCF proxy clients can be created to implement the pattern and replace the using block:
 
public class WCFProxy
    {
        public static void Using<t>(Action<t> action)
        {
            ChannelFactory<t> factory = new ChannelFactory<t>("*");

            T client = factory.CreateChannel();

            try
            {
                action(client);
                ((IClientChannel)client).Close();
                factory.Close();
            }
            catch (Exception ex)
            {
                IClientChannel clientInstance = ((IClientChannel)client);
                if (clientInstance.State == System.ServiceModel.CommunicationState.Faulted)

                {
                    clientInstance.Abort();
                    factory.Abort();
                }
                else if (clientInstance.State != System.ServiceModel.CommunicationState.Closed)
                {
                    clientInstance.Close();
                    factory.Close();
                }
                throw (ex);
            }
        }
    }
To use the class is as simple as:
 
WCFProxy.Using((delegate(IMyService client)
{
  client.DoWork();
});