Wednesday, August 22, 2007

using (wcfclient) { } kaboom!

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

No comments:

Post a Comment

About the Author

Wow, you made it to the bottom! That means we're destined to be life long friends. Follow Me on Twitter.

I am an entrepreneur and hacker. I'm a Cofounder at RealCrowd. Most recently I was CTO at Hive7, a social gaming startup that sold to Playdom and then Disney. These are my stories.

You can find far too much information about me on linkedin: http://linkedin.com/in/jdconley. No, I'm not interested in an amazing Paradox DBA role in the Antarctic with an excellent culture!