Wednesday 24 October 2012

Using task based async WCF client methods in synchronous scenarios

If you are already working with the Visual Studio 2012 you may have noticed that the dialog box for generating Service References has changed a bit. It offers an additional option to generate task based asynchronous client methods (see picture below). In VS2010 you could generate async operations for the service client as well, but in VS2012 you have the additional choice:
  • Generate asynchronous operations
    This one gives you the exact same result as choosing to generate async operations in VS2010 i.e. for each service method you will have 2 additional client methods: *Async & *Completed. One of my previous posts partially explains how to use them and provide more links on that topic.
  • Generate task-based operations
    When writing your async code this option allows you to take advantage of the Task Parallel Library (TPL) that was introduced with .Net 4. This post is not meant to be a TPL tutorial, but there are many sites explaining the concept. My personal favourite is "Introduction to Async and Parallel Programming in .NET 4" by Dr. Joe Hummel. For now it is enough to say that using tasks (i.e. TPL library) can make handling your async scenarios easier and the async code more readable/maintainable.

The interesting thing is that since .Net 4.5 and its async/await feature you can easily benefit from using task-based async operation even in fully synchronous scenarios. You may start wondering what can be advantages of using async techniques & libraries in fully synchronous scenarios. The answer is: performance! If you are using regular synchronous methods, they block current thread until it receives the response. In case of task-based operations combined with async/await feature the thread is released to the pool while waiting for the service response.

Obviously this advantage only applies in some scenarios e.g. in web applications running on IIS, where requests are handled in parallel by threads from the pool. If you are working a single threaded client app you will not benefit from this approach.

Sample code

In this post I'll re-use the sample code from my last post. I'll convert synchronous calls to my sample web service so they use task-based async operations. So, let me remind you the interface of the web service that we will use:

[ServiceContract]
public interface IStringService
{
    [OperationContract]
    string ReverseString(string input);
}
Now, let's update the service client. There is actually not much conversion that needs to be done. First, you need to ensure that the generated code includes task-based async operations (right click on service reference -> "Configure service reference"). Once you have async operations generated, you need to transform the existing code to work with tasks and use async/await feature:
public async Task<string> ReverseAsync(string input)
{
    return await _client.ReverseStringAsync(input);
}
Comparing to the original, purely synchronous method we have following changes:
  • Async keyword added to the method signature
  • Method return type changed to Task<string> (i.e. original return type 'wrapped' with Task)
  • Different service client method used: ReverseStringAsync instead of ReverseString
  • Await keyword added before the client method call
  • "*Async" suffix added to the method name (recommended convention)
These changes are enough to start taking advantage of async features of .net 4.5. We only need to update our tests, but there is only a few changes here as well.

Updated integration test:

[TestMethod]
public void TestStringHelper_Reverse()
{
    StringHelper sh = new StringHelper();
    string result = sh.ReverseAsync("abc").Result;
    Assert.AreEqual("cba", result);
}
Notice that I only added a call to .Result property as this time the method returns Task.

And the unit test:

[TestMethod]
public void TestStringHelper_Reverse()
{
    // Create channel mock
    Mock<IStringServiceChannel> channelMock = new Mock<IStringServiceChannel>(MockBehavior.Strict);

    // setup the mock to expect the ReverseStringAsync method
    channelMock.Setup(c => c.ReverseStringAsync("abc")).Returns(Task.FromResult("cba"));

    // create string helper and invoke the ReverseAsync method
    StringHelper sh = new StringHelper(channelMock.Object);
    string result = sh.ReverseAsync("abc").Result;
    Assert.AreEqual("cba", result);

    //verify that the method was called on the mock
    channelMock.Verify(c => c.ReverseStringAsync("abc"), Times.Once());
 }
The main thing to notice here is that we use Task.FromResult to create a task wrapping our sample result when mocking the client method.

Asp.Net MVC

I already mentioned that described approach will only be beneficial in some types of apps e.g. webapps running on IIS. A sample Asp.Net MVC4 controller action using our async client could look as follows:
public async Task<ActionResult> Index()
{
    ViewBag.Message = "Reversed 'abc' string: "
                      + await _stringHelper.ReverseAsync("abc");
    return View();
}
Again, notice async and await keywords added to the action method, supported in MVC4.
A detailed tutorial for using aync/await with MVC4 can be found here.

Sample code for this post on my github:
https://github.com/filipczaja/BlogSamples/tree/master/MockingWCFClientWithMoqAsync

No comments: