WCF Client Closal & Disposal

Say you’re consuming a WCF service. You’ve added a service reference, and you’ve got a client proxy. It implements IDisposable. So, when it’s time to use it, you should just chuck it in a using statement and not worry about additional resource cleanup, right?

Not so fast. There can be problems with the using statement. The problem is prevalent enough to warrant an article on MSDN demonstrating the improper use of using to automatically clean up resources when using a typed client.

So what should you be using instead of using? One option, which is outlined in the aforementioned MSDN article, is to use a try/catch block. If an exception occurs while closing the client, the client’s Abort method should be called. MSDN’s guidance suggests reporting errors and calling Abort for expected exceptions and calling Abort then re-throwing unexpected exceptions. The article explains, “Typically there is no useful way to handle unexpected errors, so typically you should not catch them when calling a WCF client communication method.”

// MSDN recommendation for WCF client cleanup
try
{
    client.Close();
}
catch (CommunicationException e)
{
    ...
    client.Abort();
}
catch (TimeoutException e)
{
    ...
    client.Abort();
}
catch (Exception e)
{
    ...
    client.Abort();
    throw;
}

There’s a lot of quick & dirty advice online that suggests using a try/finally block to first Close the client if it’s not in a faulted state, then Abort it if it’s not in a closed state. This is probably fine for small, simple applications, but hiding all exceptions can lead to maintenance woes later by reducing the visibility of underlying problems.

// effective but hides errors
try
{
    if (client.State != CommunicationState.Faulted)
    {
        client.Close();
    }
}
finally
{
    if (client.State != CommunicationState.Closed)
    {
        client.Abort();
    }
}

I like the suggestion laid out in this blog article. The author suggests re-implementing IDisposable in a partial class. The problem I have with this approach is that it may be confusing to other developers. When the client is used in the application, it will be wrapped in a using. There’s no good way for a developer to know whether that class has been properly re-implemented without doing further investigation. I think it’s easier for developers to have a hard rule: don’t use using with WCF clients.

So, instead of using a partial class, I’d suggest creating a wrapper that implements IDisposable. Developers using the client don’t need to worry about closing connections or error-handling; they can just throw a using around it an move on.

Here’s what that might look like. You could implement the service contract interface to ensure all methods are exposed, or have a generic method that accepts a lambda expression.

// An IDisposable client wrapper
public class Client : IDisposable
{
    private WcfClient _client;
    
    public Client()
    {
        _client = new WcfClient();
    }
    
    public void SomeMethod()
    {
        _client.SomeMethod();
    }
    
    void IDisposable.Dispose()
    {
        Dispose(true);
    }
 
    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (_client == null)
            {
                return;
            }
            
            try
            {
                if (_client.State != CommunicationState.Faulted)
                {
                    _client.Close();
                }
            }
            catch (CommunicationException e)
            {
                //...
                _client.Abort();
            }
            catch (TimeoutException e)
            {
                //...
                _client.Abort();
            }
            catch (Exception e)
            {
                //...
                _client.Abort();
                throw;
            }
            finally
            {
                if (_client.State != CommunicationState.Closed)
                {
                    _client.Abort();
                }
                _client = null;
            }
        }
    }
 
    ~Client()
    {
        Dispose(false);
    }
}
Advertisements

2 thoughts on “WCF Client Closal & Disposal”

  1. thanks for the post… I like the wrapper idea. Wondering though why you need to implement the Finalizer.. I see other similar examples without it.

Leave a comment

Fill in your details below or click an icon to log in:

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