Making your WCF Service Task based without changing its code

December 9, 2014

no comments

WCF is a very powerful framework, it allows you to control your service behavior without even touch your code.

You can change bindings, protocols, Timeouts and much more only through configurations and environmental changes.

WCF also supports writing Task based asynchoronous service, for example:

 

Service Side:

    [ServiceContract]
    public interface ICalculator
    {

        [OperationContract]
        Task AddAsync(int left,int right);
    }

 

    public class Calculator : ICalculator
    {
        public async Task AddAsync(int left, int right)
        {
            await Task.Delay(TimeSpan.FromSeconds(2));
            return left + right;
        }
    }

 

Client Side:

var channelFactory = new ChannelFactory("BasicHttpBinding_ICalculator");
var calculator = channelFactory.CreateChannel();
var result = await calculator.AddAsync(1, 5);
Console.WriteLine("1 + 5 = {0}", result);

App.Config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_ICalculator" />
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:27866/Calculator.svc" binding="basicHttpBinding"
                bindingConfiguration="BasicHttpBinding_ICalculator" contract="Contracts.ICalculator"
                name="BasicHttpBinding_ICalculator" />
        </client>
    </system.serviceModel>
</configuration>

Thats Great, but…

Task based like we just saw is available only from .NET 4.5 and it requires that service itself will implement the method using Tasks – wither by using the async keyword or by actually returning a Task.

It turns out that youc can still add the Task asynchronicity even if the Service side does it’s work synchronously.

All you ned to do is to add an interface with the Async methods and specify that the Async methods are pointing to the synchronous method.

 

Service Side:

    [ServiceContract]
    public interface ICalculator
    {
        [OperationContract]
        Task<int> AddAsync(int left,int right);

        [OperationContract]
        int Minus(int left, int right);
    }


    [ServiceContract]
    public interface ICalculatorAsync:ICalculator
    {
        [OperationContract(
            Action = "http://tempuri.org/ICalculator/Minus",
            ReplyAction = "http://tempuri.org/ICalculator/MinusResponse")]
        Task<int> MinusAsync(int left, int right);
    }
 public class Calculator : ICalculator
    {
        public async Task<int> AddAsync(int left, int right)        {    //No change from before    }

        public int Minus(int left, int right)
        {
            return left - right;
        }
    }

Client Side:

var channelFactory = new ChannelFactory&lt;ICalculatorAsync&gt;(&quot;BasicHttpBinding_ICalculator&quot;);
var Calculator = channelFactory.CreateChannel();
var result = await Calculator.MinusAsync(5, 1);
Console.WriteLine(&quot;5 - 1 = {0}&quot;, result);

 

App.Config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_ICalculator" />
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:27866/Calculator.svc" binding="basicHttpBinding"
                bindingConfiguration="BasicHttpBinding_ICalculator" contract="Contracts.ICalculatorAsync"
                name="BasicHttpBinding_ICalculator" />
        </client>
    </system.serviceModel>
</configuration>

in the example i added a method with the name Minus. The method is synchronous and the Calculator service didnt had to do anything special.
I created a new interface that declare an Async method and method was decorated with the OperationContract attribute, and i specified that the Action of that method is actually the Synchronous version of Minus, and i also set the ReplyAction to be the ReplyAction of Synchronous version of Minus.

On the client side i changed the App.Config so that the endpoint is now looking for ICalculatorAsync interface when talking to the Service.

Now, when the client code create a channel, what is created is a proxy that implement the ICalculatorAsync interface, and client side WCF client is smart enough to understand how the to work against the Task based version.

Summary

Sometimes you find yourself with a need to work with some synchronous service, with WCF you have the power to still enjoy the benefits of async-await and Task based method without the need to change the service side. The method i showed enable you to create the Async interface even on the client side and everything will work beutifully.

The example can be found in https://github.com/tamirdresher/EasyTaskBasedWCFService

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*