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
