Your browser may have trouble rendering this page. See supported browsers for more information.

This page shows the source for this entry, with WebCore formatting language tags and attributes highlighted.

Title

Dealing with improper disposal in WCF clients

Description

There's an old problem in generated WCF clients in which the <c>Dispose()</c> method calls <c>Close()</c> on the client irrespective of whether there was a fault. If there was a fault, then the method should call <c>Abort()</c> instead. Failure to do so causes another exception, which masks the original exception. Client code will see the subsequent fault rather than the original one. A developer running the code in debug mode will have be misled as to what really happened. You can see <a href="http://geekswithblogs.net/DavidBarrett/archive/2007/11/22/117058.aspx" author="David Barrett" source="">WCF Clients and the "Broken" IDisposable Implementation</a> for a more in-depth analysis, but that's the gist of it. This issue is still present in the <c>ClientBase</c> implementation in .NET 4.5.1. The linked article shows how you can add your own implementation of the <c>Dispose()</c> method in each generated client. An alternative is to use a generic adaptor if you don't feel like adding a custom dispose to every client you create.<fn> <code> <b>public class</b> SafeClient<t> : IDisposable <b>where</b> T : ICommunicationObject, IDisposable { <b>public</b> SafeClient(T client) { <b>if</b> (client == <b>null</b>) { <b>throw new</b> ArgumentNullException("client"); } Client = client; } <b>public</b> T Client { <b>get</b>; <b>private set</b>; } <b>public void</b> Dispose() { Dispose(<b>true</b>); GC.SuppressFinalize(<b>this</b>); } <b>protected virtual void</b> Dispose(<b>bool</b> disposing) { <b>if</b> (disposing) { <b>if</b> (Client != <b>null</b>) { <b>if</b> (Client.State == CommunicationState.Faulted) { Client.Abort(); } <b>else</b> { Client.Close(); } Client = <b>default</b>(T); } } } } </code> To use your WCF client safely, you wrap it in the class defined above, as shown below. <code> <b>using</b> (<b>var</b> safeClient = <b>new</b> SafeClient<systemloginserviceclient>(<b>new</b> SystemLoginServiceClient(...))) { <b>var</b> client = safeClient.Client; // Work with "client" } </code> If you can figure out how to initialize your clients without passing parameters to the constructor, you could slim it down by adding a "new" generic constraint to the parameter T in <c>SafeClient</c> and then using the <c>SafeClient</c> as follows: <code> <b>using</b> (<b>var</b> safeClient = <b>new</b> SafeClient<systemloginserviceclient>()) { <b>var</b> client = safeClient.Client; // Work with "client" } </code> <hr> <ft>The code included in this article is a sketch of a solution and has not been tested. It does compile, though.</ft>