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.