wcf
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!
Create a WCF service.
[ServiceContract]public interface IGoodBadService{ [OperationContract] void Good(); [OperationContract] void Bad();}Add a service reference to your service in another project.
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);}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!"); }}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
