WCF Client and the “using” Statement
As I was researching patterns and practices for a WCF client implementation, I came across a bug in the .Net implementation of ClientBase<T> (whether it's actually a bug is arguable). It's well documented on the web, but it could cause major headaches if you happened to miss it.
The core of the issue is that ClientBase<T> implements IDisposable. With this knowledge, just about any programmer would naturally wrap its usage in a using{} block. Digging deeper, you'll find that the ClientBase<T> Dispose() method simply calls Close() on the underlying connection. This is problematic because in certain connection states (such as "Faulted"), the Close() will fail. As I said, this is well documented elsewhere, for example: on MSDN, Stack Overflow, and here.
There are a few different solutions to this issue. I went with a simple Disposable wrapper...
// Get a disposable MyClientWrapper object using(var clientWrapper = ClientFactory.GetMyClientWrapper()) { clientWrapper.Client.DoSomething(); } public class MyClientWrapper : IDisposable { private readonly MyClient _client; public MyClientWrapper(Binding binding, Uri endpoint) { // creates an instance of MyClient, which is derived from ClientBase<T> _client = new MyClient(binding, new EndpointAddress(endpoint.ToString())); } public MyClient Client { get { return _client; } } public void Dispose() { // safe dispose with extension method (below) _client.CloseProxy(); } } // extension method for safe Close() on ClientBase<T> public static void CloseProxy(this ClientBase<T> proxy) where T : class { try { if (proxy.State != CommunicationState.Closed && proxy.State != CommunicationState.Faulted) { proxy.Close(); // may throw exception while closing } else { proxy.Abort(); } } catch (CommunicationException) { proxy.Abort(); throw; } }
November 9th, 2011 - 00:37
Kevin,
Great catch! I would extend this a little. According to MS best practices a Dispose method should not throw an exception. I would put a try/catch (with some logging) around the _client.CloseProxy() call. A resource at work to ask about WCF is Doug E. He can go on at great length about WCF and handling of the proxy