JD ConleyWriting

wcf

using (wcfclient) { } kaboom!

JD Conley
Updated July 27, 2011

I've been doing a lot of WCF development lately (love it) and ran into a bit of a stumbling block. The proxy client generated by Visual Studio 2008 Beta 2 doesn't handle fault conditions and dispose well. I have to admit, I haven't used WCF in Visual Studio 2005. If you're impatient here's the project (Visual Studio 2008 Beta 2 project): wcfwrapper.zip The situation unfolds:

The Problem - Dispose Isn't Safe!

  1. Create a WCF service.

    [ServiceContract]
    public interface IGoodBadService
    {
       [OperationContract]
       void Good();
    
       [OperationContract]
       void Bad();
    }
    
  2. Add a service reference to your service in another project.

  3. Create a service client and use it, with a "using" block (it is IDisposable, afterall).

    try
    {
       using (GoodBadServiceClient c =
           new GoodBadServiceClient())
       {
           c.Bad();
       }
    }
    catch (Exception ex)
    {
       Console.WriteLine(ex.Message);
    }
    
  4. A call to your service, for whatever reason, throws an exception.

    public class GoodBadService
       : IGoodBadService
    {
       public void Good()
       {
           throw new Exception("GOOD!");
       }
    
       public void Bad()
       {
           throw new Exception("BAD!");
       }
    }
    
  5. You get a cryptic System.ServiceModel.CommunicationObjectFaultedException instead of the real exception when using calls Dispose() on your proxy client. It reads: The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it is in the Faulted state.

The Solution - A Simple Generic Wrapper

public class ServiceProxy<TClient>
   : IDisposable
   where TClient : ICommunicationObject
{
   public ServiceProxy(TClient client)
   {
       Client = client;
   }

   public TClient Client { get; private set; }

   public void Dispose()
   {
       if (null != Client &&
           Client.State != CommunicationState.Closed &&
           Client.State != CommunicationState.Faulted)
       {
           Client.Close();
       }
   }
}

Using the wrapper is pretty straightforward, but a tad more cryptic than just using the client directly. Some of this can be avoided with a generic factory.

So, here's how you use it:

try
{
   using (ServiceProxy<GoodBadServiceClient> c
       = new ServiceProxy<GoodBadServiceClient>(
           new GoodBadServiceClient()))
   {
       c.Client.Good();
   }
}
catch (Exception ex)
{
   Console.WriteLine(ex.Message);
}

Run the project and check out the results. The wrapper gives you the actual exception, whereas "using" the client directly causes the CommunicationObjectFaultedException. Here's the project (Visual Studio 2008 Beta 2 project): wcfwrapper.zip

Written by JD Conley

I build software people want.
Based in South Lake Tahoe.