HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpCritical

What is the best workaround for the WCF client `using` block issue?

Submitted by: @import:stackoverflow-api··
0
Viewed 0 times
theforbestclientusingblockissueworkaroundwhatwcf

Problem

I like instantiating my WCF service clients within a using block as it's pretty much the standard way to use resources that implement IDisposable:

using (var client = new SomeWCFServiceClient()) 
{
    //Do something with the client 
}


But, as noted in this MSDN article, wrapping a WCF client in a using block could mask any errors that result in the client being left in a faulted state (like a timeout or communication problem). Long story short, when Dispose() is called, the client's Close() method fires, but throws an error because it's in a faulted state. The original exception is then masked by the second exception. Not good.

The suggested workaround in the MSDN article is to completely avoid using a using block, and to instead instantiate your clients and use them something like this:

try
{
    ...
    client.Close();
}
catch (CommunicationException e)
{
    ...
    client.Abort();
}
catch (TimeoutException e)
{
    ...
    client.Abort();
}
catch (Exception e)
{
    ...
    client.Abort();
    throw;
}


Compared to the using block, I think that's ugly. And a lot of code to write each time you need a client.

Luckily, I found a few other workarounds, such as this one on the (now defunct) IServiceOriented blog. You start with:

public delegate void UseServiceDelegate(T proxy); 

public static class Service 
{ 
    public static ChannelFactory _channelFactory = new ChannelFactory(""); 
    
    public static void Use(UseServiceDelegate codeBlock) 
    { 
        IClientChannel proxy = (IClientChannel)_channelFactory.CreateChannel(); 
        bool success = false; 
        try 
        { 
            codeBlock((T)proxy); 
            proxy.Close(); 
            success = true; 
        } 
        finally 
        { 
            if (!success) 
            { 
                proxy.Abort(); 
            } 
        } 
     } 
}


Which then allows:

``
Service.Use(orderService =>
{
orderService.PlaceOrder(request);
});

Solution

Actually, although I blogged (see Luke's answer), I think this is better than my IDisposable wrapper. Typical code:

Service.Use(orderService=>
{
  orderService.PlaceOrder(request);
});


(edit per comments)

Since Use returns void, the easiest way to handle return values is via a captured variable:

int newOrderId = 0; // need a value for definite assignment
Service.Use(orderService=>
  {
    newOrderId = orderService.PlaceOrder(request);
  });
Console.WriteLine(newOrderId); // should be updated

Code Snippets

Service<IOrderService>.Use(orderService=>
{
  orderService.PlaceOrder(request);
});
int newOrderId = 0; // need a value for definite assignment
Service<IOrderService>.Use(orderService=>
  {
    newOrderId = orderService.PlaceOrder(request);
  });
Console.WriteLine(newOrderId); // should be updated

Context

Stack Overflow Q#573872, score: 142

Revisions (0)

No revisions yet.