patterncsharpCritical
What is the best workaround for the WCF client `using` block issue?
Viewed 0 times
theforbestclientusingblockissueworkaroundwhatwcf
Problem
I like instantiating my WCF service clients within a
But, as noted in this MSDN article, wrapping a WCF client in a
The suggested workaround in the MSDN article is to completely avoid using a
Compared to the
Luckily, I found a few other workarounds, such as this one on the (now defunct) IServiceOriented blog. You start with:
Which then allows:
``
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:
(edit per comments)
Since
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 updatedCode 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 updatedContext
Stack Overflow Q#573872, score: 142
Revisions (0)
No revisions yet.