title: What is the Correct Way to Dispose a WCF Proxy?
body: <p>I have been struggling with WCF Proxies. What is the correct way to Dispose a WCF Proxy? The answer is not trivial.</p>
  
  <p><strong>System.ServiceModel.ClientBase violates Microsoft's own Dispose-pattern</strong></p>
  
  <p><code>System.ServiceModel.ClientBase&lt;TChannel&gt;</code> <em>does</em> implement <code>IDisposable</code> so one must assume that it should be disposed or used in a <code>using</code>-block. These are best practices for anything disposable. The implementation is explicit, however, so one does have to explicitly cast <code>ClientBase</code> instances to <code>IDisposable</code>, clouding the issue.</p>
  
  <p>The biggest source of confusion, however, is that calling <code>Dispose()</code> on <code>ClientBase</code> instances that faulted, <em>even channels that faulted because they never opened in the first place</em>, will result in an exception being thrown. This, inevitably, means that the meaningful exception explaining the fault is immediately lost when the stack unwinds, the <code>using</code> scope ends and <code>Dispose()</code> throws a meaningless exception saying that you can't dispose a faulted channel.</p>
  
  <p>The above behaviour is anathema to the <em>dispose</em> pattern which states that objects must be tolerant of multiple explicit calls to <code>Dispose()</code>. (see <a href="http://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.110).aspx">http://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.110).aspx</a>, "<em>...allow the <code>Dispose(bool)</code> method to be called more than once. The method might choose to do nothing after the first call.</em>")</p>
  
  <p>With the advent of <em>inversion-of-control</em>, this poor implementation becomes a real problem. I.O.C. containers (specifically, Ninject) detect the <code>IDisposable</code> interface and call <code>Dispose()</code> explicitly on activated instances at the end of an injection scope.</p>
  
  <p><strong>Solution: Proxy ClientBase and Intercept calls to Dispose()</strong></p>
  
  <p>My solution was to proxy <code>ClientBase</code> by subclassing <code>System.Runtime.Remoting.Proxies.RealProxy</code> and to hijack or intercept calls to <code>Dispose()</code>. My first replacement for <code>Dispose()</code> went something like this:</p>
  
  <pre><code>if (_client.State == CommunicationState.Faulted) _client.Abort();
  else ((IDisposable)_client).Dispose();
  </code></pre>
  
  <p>(Note that <code>_client</code> is a typed reference to the target of the proxy.)</p>
  
  <p><strong>Problems with NetTcpBinding</strong></p>
  
  <p>I thought that this had nailed it, initially, but then I discovered a problem in production: under certain scenarios that were fiendishly difficult to reproduce, I found that channels using a <code>NetTcpBinding</code> were not closing properly in the unfaulted case, even though <code>Dispose</code> was being called on <code>_client</code>.</p>
  
  <p>I had an ASP.NET MVC Application using my proxy implementation to connect to a WCF Service using a <code>NetTcpBinding</code> on the local network, hosted within a Windows NT Service on a service cluster with only one node. When I load-tested the MVC Application, certain endpoints on the WCF Service (which was using port-sharing) would stop responding after a while.</p>
  
  <p>I struggled to reproduce this: the same components running across the LAN between two developer's machines worked perfectly; a console application hammering the real WCF endpoints (running on the staging service cluster) with many processes and many threads in each worked; configuring the MVC Application on the staging server to connect to the endpoints on a developer's machine worked under load; running the MVC Application on a developer's machine and connecting to the staging WCF endpoints worked. The last scenario only worked under IIS Express, however, and this was a breakthrough. The endpoints would sieze up when load-testing the MVC Application under full-fat IIS on a developer's machine, connecting to the staging service cluster.</p>
  
  <p><strong>Solution: Close the Channel</strong></p>
  
  <p>After failing to understand the problem and reading many, many pages of the MSDN and other sources that claimed the problem shouldn't exist at all, I tried a long-shot and changed my <code>Dispose()</code> work-around to...</p>
  
  <pre><code>if (_client.State == CommunicationState.Faulted) _client.Abort();
  else if (_client.State == CommunicationState.Opened)
  {
      ((IContextChannel)_client.Channel).Close();
      ((IDisposable)_client).Dispose();
  }
  else ((IDisposable)_client).Dispose();
  </code></pre>
  
  <p>... and the problem stopped occurring in all test setups and under load in the staging environment!</p>
  
  <p><strong>Why?</strong></p>
  
  <p>Can anyone explain what might have been happening and why explicitly closing the <code>Channel</code> before calling <code>Dispose()</code> solved it? As far as I can tell, this shouldn't be necessary.</p>
  
  <p>Finally, I return to the opening question: What is the correct way to Dispose a WCF Proxy? Is my replacement for <code>Dispose()</code> adequate?</p>