The .NET Endpoint

Blog by the .NET and AppFabric teams about WCF and WF development, deployment, and management

Simplified Asynchronous Programming Model in WCF with async/await

Simplified Asynchronous Programming Model in WCF with async/await

Rate This
  • Comments 9

Managing multiple asynchronous operations in WCF is currently very complex regardless of whether you use the existing event or Begin/End asynchronous patterns. In fact, both internal and external customers frequently ask about how to implement simple coordination of WCF operations, and even though sending multiple requests to a WCF backend is a core scenario, WCF does not provide a satisfactory solution. 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 very common communication-oriented scenarios that require managing multiple outstanding asynchronous operations:

  • Execute multiple async operations in parallel and continue when they are all done, either successfully, failed, or timed out.
  • Execute sequence of asynchronous operations, stopping if one of the operations fails or times out.
  • Nest multiple asynchronous operations.
  • Combine asynchronous operations with timers for easy polling at regular intervals.

However, regardless of the current complexity, WCF developers have to use asynchronous requests to write robust implementations, and doing that today is a difficult challenge.

During PDC’10, the C# and VB.NET teams released the Visual Studio Async CTP, which aims at providing a new simplified model for doing asynchronous programming in both languages. In WCF, we have decided to adopt this model because we believe it removes the barrier to writing WCF robust asynchronous application, has the least possible learning curve from the existing CLR APM pattern, and provides a simple and consistent model for coordinating, submitting and managing multiple asynchronous WCF operations.

WCF vNext will adopt the Async model in both the client and the server side, and provide new Task-based overloads for some of the most used asynchronous APIs:

Server Side

WCF service developers will be able to define asynchronous operation contracts that return Task/Task<T>:

[ServiceContract]
public interface IServiceContract
{
    [OperationContract]
    Task<string> HelloAsync(string name);
}

As you may notice, there is no need to switch OperationContract.AsyncPattern to true anymore (yeah!), or define Begin/End methods in your service contract.

In the service contract implementation, WCF service developers will be able to implement that operation contract as an async method, and create/start new tasks, etc.:

namespace WCFServiceModelSamples
{
    public class HelloService : IServiceContract
    {
        public async Task<string> HelloAsync(string name)
        {
            return await Task.Factory.StartNew(() => "hello " + name);
        }
    }
}

There is no need to explicitly implement any Begin/End method, IAsyncResult objects or any type of callback. Internally, WCF will add an operation invoker to the dispatcher that will be able to process Task-based operations, which will make all work transparently to the user.

Client side

The support for generating Task-based operations on the client side will be available to users who rely on proxies generated by our client generation tools (svcutil.exe or Add Service Reference), as well as to users who prefer to directly use ChannelFactory<T>.

The client proxy generation tools will generate Task-based overloads for all operations in the contract by default. This means that WCF client application developers will not need to switch any new knob in the tools to be able to use this model. But they will always be able to opt-out with the /syncOnly switch if they wish. The output of executing ’svcutil.exe /async’ will still generate Begin/End methods, as it does today. WCF users should not experience any breaking change in their code. Finally, it is worth mentioning that WCF developers will be able to generate Task-based overloads as well by using ServiceContractGenerator.

From the implementation side, the support for executing Tasks will be implemented directly in the channel, which makes the generated client proxy code look as clean as this:

public partial class HelloServiceClient : ClientBase<IServiceContract>,
                                          IServiceContract {
    public System.Threading.Tasks.Task<string> HelloAsync(int value) {
        return base.Channel.HelloAsync(value);
    }
    ...
} 

Finally, a code snippet for a WCF client application calling asynchronously the WCF service defined above will look like the following:

namespace MyAsyncApplication
{
    class AsyncClientApp
    {
        static void Main(string[] args)
        {
            string[] names = { "daniel", "john", "tarae" };

            PrintHelloNames(names)
                .ContinueWith(delegate { Console.WriteLine("Done."); });

            Console.WriteLine("Hit ENTER to exit.\n");
            Console.ReadLine();
        }

        static async Task PrintHelloNames(string[] names)
        {
            foreach (string name in names)
            {
                try
                {
                    Task<string> task = new HelloServiceClient().HelloAsync(name);
                    if (task == await Task.WhenAny(task, Task.Delay(1000)))
                    {
                        Console.WriteLine(await task);
                    }
                    else Console.WriteLine("Timed out");
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
            }
        }
    }
}

New Task-based public APIs

Even though WCF developers will be able to add their own Task-based wrappers for existing asynchronous APIs based on the Begin/End model via Task.Factory.FromAsync, WCF will provide Task-based overloads for some of the main asynchronous public APIs. In particular, for those in the MEX and Discovery client, for consistency with the tools-generated clients:

  • System.ServiceModel.Description.MetadataExchangeClient.BeginGetMetadataAsync
  • System.ServiceModel.Discovery.AnnouncementClient.BeginAnnounceOnlineAsync
  • System.ServiceModel.Discovery.AnnouncementClient.BeginAnnounceOfflineAsync
  • System.ServiceModel.Discovery.DiscoveryClient.FindTaskAsync
  • System.ServiceModel.Discovery.DiscoveryClient.ResolveTaskAsync

 

That’s all folks! Feedback is always encouraged. Please let us know what you think about this new programming model in WCF. Welcome to the new asynchronous programming world!

Amadeo Casas Cuadrado
Program Manager, WCF

  • Wow! nice article! I've been searching for this topic for a while and this article just clarified most of my doubts. Thank you, Casas

  • Looks really nice! Currently creating a high performance async wcf service that does a few database calls and such is very difficult to say the least.  This should simplify that task a lot. Now, as always, if it only was released yesterday ;)

  • This is all great news. A question though (i think) is worth asking, and it's related to threading in service operations.

    In the context of a wcf service operation implementation, as of today, besides the difficulties in programming continuations via custom IAsyncResult implementations, there are some threading implications you have to take into deep consideration. If, for example, you have part of your code that does not run asynchronously (say you make for instance, an async db call, and then you have to populate an object hierarcy based on the result), and you don't need a specific synchronization context, than, the best option, would be to have that portion of the code, to be run by one of the completion ports thread used by the wcf runtime. Unfortunately, unless you are implementing the service operation as an Async Activity (inside a WF4 service), you have no easy way of doing so (IOThreadScheduler and related api are not publicly available).

    Now, my question is: Given the current implementation of async methods, by the c# compiler, which (as far as i've read), uses a current sync context (is any) to post the execution of the non async code blocks in an async method, wil the new IOperationInvoker implementation setup an appropriate synchronization context (if none provided) so that, those code blocks will be run in the context of an IOCP thread?

    Of course I hope the anser will be yes.

    Antonello Tesoro

    Enterprise Software Architect

  • WCF is adopting this new asynchronous programming model at the level of abstraction of Task/Task<T>, which means we will not do anything different about synchronization context from what Task/Task<T> will do.

    That said, WCF already has today a very sophisticated and optimized infrastructure for asynchronous execution of operations, and with the adoption of this new model we are hoping the user experience will greatly be simplified by wrapping the existing foundation into Tasks. We are being very careful with performance and making sure that all the requirements around performance are satisfied.

  • Thank you for your first answer.

    I’d like to clarify my question a little bit though, because it has not only to do with threading issues but also with call context. As you know (much better than me :)), when invoking a service operation, the wcf runtime will setup the context in which the service operation will run. The setup is made by the following steps:

     - apply the HostingIntegrationContext

     - set the Current OperationContext

     - setup the Transaction Scope (if required)

     - ask all the ICallContextInitializers to initialize the context

     - set the current principal

     - start impersonation (if required).

    (The runtime will also cleanup the aforementioned context as the call returns).

    In case of an async invocation, the runtime will repeat those steps for both the Begin and the End Method. Prior to the context setup, the runtime will also make sure the call will happen in the right thread (via a SynchronizationContext if one provided, or by the use of IOCP).

    When it comes to operations implemented via the new TAP though, those operations will contain both async calls (mostly IO bound) and computations, as in the following example.

    public async Task<OpReturnType> MyServiceOperation(…) {

       OpReturnType result = default(OpReturnType);

       // do something

      await Metod1Async(…);

       // do some other processing

       await Method2Async(…);

       // do some final processing

       return result;

    }

    As soon as the execution reaches the first “await”, the method will return, and the execution will resume in whichever thread, the async implementation of Method1Async will call back into the code. Now the questions are:

    - In which thread should the “do some other processing” and “do some final processing” code blocks, be run?

    - should the runtime set up the context before running those code blocks?

    The fact is, that TAP based implementations are in fact Continuations and, as such, the execution will be split into multiple steps (not only a Begin and an End). Moreover, given the fact that the compiler, gives devs the illusion of writing a standard method, it’s very likely that people will expect to be able to do what they normally do, in whichever part of the method implementation (for example is highly probable that a dev will think he can call OperationContext.Current or Thread.CurrentPrincipal in “do some other processing” and obtain the correct result).

    I’m sure you guys, in the Wcf team, are already thinking about those issues and will come out with the best possible solution.

    Antonello Tesoro

    Enterprise Software Architect

  • The processing code that happens after a task is awaited may or may not be executed by the same thread pool thread. In any case, the execution context is captured when the task is awaited, and when the task completes the corresponding execution context will be set up again to execute the continuation code block.

    Thanks for your feedback.

  • Now Async is devloper friendly. Thanks for sharing.

  • Hi,

    When, inside of Task, we have an I/O operation (database call), will this task run on IOCP thread?!

  • Yes, I/O operation will run on IOCP thread.

Page 1 of 1 (9 items)