WCF Dispose problem with using statement

Free ECM Educational Resources
Brought to you by KnowledgeLake
Data Connector by BoostSolutions
Access external data within SharePoint
20+ Premium Web Parts
to enhance your SharePoint 2007 and 2010 performance. Click here.

WCF client cannot be used inside a Using block because they may unexpectedly throw an exception. Even if you catch the exception, it is possible that a connection will be left open.

Why is this IDisposable implementation so different from all the others in the .NET Framework.

The first problem with WCF clients is that the Close/Dispose method can throw an exception. This makes the Dispose method unsafe to call from a Finally block. Close() take a Timeout and has an async version, and also Close() can throw Exceptions. Abort() conversely is not supposed to block (or throw any expected exceptions), and therefore doesn’t have a timeout or an async version

Even worse, there is a chance that the Close/Dispose method can leave the connection open if Abort isn’t called. If too many connections are left open, this can lead to application instability. The solution given on MSDN is not safe!

In short, Close() will dispose the resources friendly and Abort() will do this ungracefully. Because Close() may throw some exceptions such as CommunicationException and TimeoutException, so the code snippet on the client side would be like this:

MyClient client = null;
try
{
  client = new MyClient();
  result = client.Bronsystemen();
}
catch (EndpointNotFoundException)
{
  if (client != null) client.Abort();
}
catch (FaultException)
{
  if (client != null) client.Abort();
}
catch (TimeoutException)
{
  if (client != null) client.Abort();
}
catch (CommunicationException)
{
  if (client != null) client.Abort();
}
catch (Exception)
{
  if (client != null) client.Abort();
}
finally
{
  if (client != null) client.Close();
}

Side effects of implementing the Close method only in the Try block is that a Code Analysis rule CA2000 is given. To solve this you need the move the Close method to the Finally block. However the Close method can throw an exception that will go up.

A workaround is to create an extension method that will close the connection. The Close method will be called within a Try-catch block.

public static class Extensions
{
    public static void CloseConnection(this ICommunicationObject client)
    {
        if (client.State != CommunicationState.Opened)
        {
            return;
        }
        try
        {
            client.Close();
        }
        catch (CommunicationException ex)
        {
            client.Abort();
        }
        catch (TimeoutException ex)
        {
            client.Abort();
        }
        catch (Exception ex)
        {
            client.Abort();
            throw;
        }
    }
}

Leave a Reply