Friday, 16 August 2013

Pattern for calling WCF service using async/await

Pattern for calling WCF service using async/await

I generated a proxy with task-based operations.
How should this service be invoked properly (disposing of the
ServiceClient and the OperationContext afterwards) using async/await?
My first attempt was:
public async Task<HomeInfo> GetHomeInfoAsync(DateTime timestamp)
{
using (var helper = new ServiceHelper<ServiceClient, ServiceContract>())
{
return await helper.Proxy.GetHomeInfoAsync(timestamp);
}
}
Being ServiceHelper a class which creates the ServiceClient and the
OperationContextScope and disposes of them afterwards:
try
{
if (_operationContextScope != null)
{
_operationContextScope.Dispose();
}
if (_serviceClient != null)
{
if (_serviceClient.State != CommunicationState.Faulted)
{
_serviceClient.Close();
}
else
{
_serviceClient.Abort();
}
}
}
catch (CommunicationException)
{
_serviceClient.Abort();
}
catch (TimeoutException)
{
_serviceClient.Abort();
}
catch (Exception)
{
_serviceClient.Abort();
throw;
}
finally
{
_operationContextScope = null;
_serviceClient = null;
}
However, this failed miserably when calling two services at the same time
with the following error: "This OperationContextScope is being disposed on
a different thread than it was created."
MSDN says:
Do not use the asynchronous "await" pattern within a OperationContextScope
block. When the continuation occurs, it may run on a different thread and
OperationContextScope is thread specific. If you need to call "await" for
an async call, use it outside of the OperationContextScope block.
So that's the problem! But, how do we fix it properly?
This guy did just what MSDN says. My problem with his code, is that he
never calls Close (or Abort) on the ServiceClient.
I also found a way of propagating the OperationContextScope using a custom
SynchronizationContext. But, besides the fact that it's a lot of "risky"
code, he states that:
It's worth noting that it does have a few small issues regarding the
disposal of operation-context scopes (since they only allow you to dispose
them on the calling thread), but this doesn't seem to be an issue since
(at least according to the disassembly), they implement Dispose() but not
Finalize().
So, are we out of luck here? Is there a proven pattern for calling WCF
services using async/await AND disposing of BOTH the ServiceClient and the
OperationContextScope? Maybe someone form Microsoft can help.
Thanks!

No comments:

Post a Comment