Building an Async WCF Service in .NET 4.5

In the .NET Framework 4.0 version of WCF, managing multiple asynchronous operations, for example in the form of WCF and HTTP request/response operations, is currently very complex regardless of whether you use the existing event or Begin/End asynchronous pattern. The amount of code needed to facilitate even simple coordination tasks is large and prone to bugs handling errors and timeouts. Yet there are some common communication oriented scenarios that require managing multiple outstanding asynchronous operations:

  1. Execute multiple async operations in parallel and continue when they are all done (either successfully, failed, or timed out).
  2. Execute sequence of async operations, stopping if one of the operations fails or times out.
  3. Nest multiple async operations (first do A, then take result and feed to B etc.).
  4. Combine async operations with timers for easy polling at regular intervals.

The task-based asynchronous programming model first introduced in the .NET Framework 4.0 provides a simple abstraction for the definition, coordination, and management of these operations. As such, providing a first-class asynchronous development experience using tasks should make the above scenarios much simpler to realize.

In order to create an asynchronous service operation, the service developer need only define a service operation that returns an instance of either Task or Task<T>. The decision on whether to return Task or Task<T> depends on whether or not the service operation returns a value. For operations which specify void, Task should be retuned. For service operations that return a value, Task<T> should be retuned.

For task-based methods, if the OperationContractAttribute specifies a name, the name will be used as is. If no name is specified on the OperationContractAttribute, the method name will be used. If the method name terminates with the string “Async”, “Async” will be truncated from the method name and the resulting string will be used as the operation name. This is to avoid having a method like “FooAsyncAsync” on the client after proxy code generation.

If a service like the one below is written, an InvalidOperationException will be thrown because the task-based method has the same name as the sync and async methods.  As a result, a service of the type below would not be supported.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
[ServiceContractAttribute(Namespace = "http://microsoft.samples")]
public interface ISampleService
{
[OperationContractAttribute]
string SampleMethod(string msg);
 
[OperationContractAttribute(AsyncPattern = true)]
IAsyncResult BeginSampleMethod(string msg, AsyncCallback callback,
object asyncState);
 
string EndSampleMethod(IAsyncResult result);
 
[OperationContractAttribute(Name = "SampleMethod")]
Task<string> SampleMethodAsync(string msg);
}

The following illustrates use of a task-basd asynchronous service operation which in turns calls out asynchronously to 2 external services, waits for both services to return, then calculates and returns a value based on the return values of the 2 external services.

1 2 3 4 5 6 7 8 9 10 11 12
public async Task<double> CalculateShippingSubtotalAsync(int productID, string postalCode)
{
var productServiceProxy = new ProductServiceClient();
var shippingServiceProxy = new ShippingServiceClient();
 
var t = productServiceProxy.GetProductByIDAsync(productID);
var t2 = shippingServiceProxy.GetShippingCostForPostalCodeAsync(postalCode);
 
await Task.WhenAll(t, t2);
 
return t.Result.UnitPrice + t2.Result;
}

This service operation leverages the Task.WhenAll combinator in order to wait for the completion of both asynchronous external service calls in a manner that does not block the thread of execution. The C# 5 async and await keywords are then used to return identify the service operation as asynchronous and define the operation which adds the product unit price and the shipping price as a continuation.

After proxy generation, calling the service looks boringly good:

paymentServiceClient.CalculateShippingSubtotal(productId, postalCode);

About Howard Dierking

I like technology...a lot...
This entry was posted in Async, WCF. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • sted1234

    What is the advantage of writing the method following way? Task.Factory.StartNew will anyway block your threadpool thread for the duration of the longRunningOperation?
    public Task SampleMethodAsync(string msg)

    {
           return await Task.Factory.StartNew(() => {
                          longRunningOperation();
                          return “hello ” + msg;
           });

    }

  • Anonymous

    Hmm – I just looked through the current MSDN docs and you’re right – I don’t see anything.  I’ll check with our docs team to see if there’s something coming.  However, I think that you’ll find that this post/code will look strikingly similar to the official SDK samples when they are available :)

  • Jim

    Hi

    Thanks for the article.

    Do you have any references to articles from Microsoft regarding WCF services written using the new async patterns in .NET 4.5. How you’ve explained this certainly seems consistent with everything else I’ve read, but I’ve been unable to find anything from MS on the subject.

    Kind Regards

    Jim