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

Monday 15 October 2012

Mocking WCF client with Moq

Performing basic web service calls from your code using WCF is relativelly easy. All you have to do is add a new service reference to your project, pointing to the service url. WCF will automatically generate a client class for you, that you can use to call service methods.

The web service

Let's say we have a web service that performs various string transformation e.g. reverses specified strings (obviously it's not a real life scenario, as you wouldn't normally call a web serviec to do that). The service implements the following interface:

[ServiceContract]
public interface IStringService
{
    [OperationContract]
    string ReverseString(string input);
}
In the sample code for this post I created a basic WCF implementation of that service. However, the service itself doesn't need to be created using WCF, as long as it's using SOAP.

The client

The simplest class that consumes this service could look as follows:
public class StringHelper
{
    StringServiceClient _client;

    public StringHelper()
    {
        _client = = new StringServiceClient();
    }

    public string Reverse(string input)
    {
        return _client.ReverseString(input);
    }
}
The StringServiceClient is a class generated automatically when adding a service reference. All you have to do is istantiate it and call the chosen method.

There is one issue with that approach though: you cannot unit test your StringHelper.Reverse method, without actually calling the web service (because classes are strongly coupled). When writing proper unit tests you should mock all the class dependencies, so you can only focus on a single unit of code. Otherwise it becomes an integration test.

When using Moq you can only mock interfaces or virtual methods. The generated StringServiceClient doesn't implement any interface that would expose the service contract. Also, methods generated in that class are not virtual.

Luckly enough the code generated when adding the service reference contains the Channel interface that we can use. The channel interface extends the service contract interface, so you can invoke all service methods using its implementation. This mean we can update the client app can to remove the tight coupling:

public class StringHelper
{
    IStringServiceChannel _client;

    public StringHelper()
    {
        var factory = new ChannelFactory<IStringServiceChannel>("BasicHttpBinding_IStringService");
        _client = factory.CreateChannel(); 
    }

    public StringHelper(IStringServiceChannel client)
    {
        _client = client;
    }

    public string ReverseString(string input)
    {
        return _client.ReverseString(input);
    }
}
As you can see, instead of working with the generated client we create a channel instance using ChannelFactory and the binding name "BasicHttpBinding_IStringService". The binding name can be found in the app.config file. The app.config file is automatically updated with WCF enpoint configuration when adding the service reference.

Testing

A simple integration test for our client code:
[TestMethod]
public void TestStringHelper_Reverse()
{
    StringHelper sh = new StringHelper();
    string result = sh.Reverse("abc");
    Assert.AreEqual("cba", result);
}
This test would work with both versions of the client presented above.

Now for the actuall unit tests that mocks the service channel object using Moq:

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

    // setup the mock to expect the Reverse method to be called
    channelMock.Setup(c => c.ReverseString("abc")).Returns("cba");

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

    //verify that the method was called on the mock
    channelMock.Verify(c => c.ReverseString("abc"), Times.Once());
}

Sample code for the service, client & test on github:
https://github.com/filipczaja/BlogSamples/tree/master/MockingWCFClientWithMoq