简体   繁体   中英

Async CTP - How can I use async/await to call a wcf service?

If I call a WCF service method I would do something like this:

proxy.DoSomethingAsync();
proxy.DoSomethingAsyncCompleted += OnDoSomethingAsyncCompleted;

How could I do the same using the new async ctp? I guess I would need something like proxy.DoSomethingTaskAsync or proxy.DoSomethingAsync().ToTask() ? The web service call needs to return a Task<T> to be able to use the await keyword, but how??

In the CTP there are factory methods that do the work of turning regular APM functions (Begin/End) into ones that are compatible with the new async keyword, for instance:

Stream s = new FileStream("C:\test.txt", FileMode.CreateNew);
byte []buffer = new byte[100];
int numBytesRead = await Task<int>.Factory.FromAsync(s.BeginRead, s.EndRead, buffer, 0, buffer.Length, null);

So in your case you can do the equivalent and then you'd then call it like so:

async proxy.DoSomethingTaskAsync()

See this thread on the CTP discussion group for more info

An asynchronous service using async-await is very responsive as it can interleave many client calls and execute them in parallel (2). Despite this, the service can run fully thread-safe on one thread (3) and can be a singleton service (1) or a service object created by the framework for a session or a call only.

When implementing the service, please note the ServiceBehaviourAttributes (1)...(3) :

    [ServiceContract( Namespace="X", Name="TheContract" )]
    public interface IAsyncContractForClientAndService
    {
        [OperationContract]
        Task<TResponse> SendReceiveAsync( TRequest req );
    }



    [ServiceBehavior (InstanceContextMode = InstanceContextMode.Single, // (1)
                      // also works with InstanceContextMode.PerSession or PerCall
                      ConcurrencyMode     = ConcurrencyMode.Multiple,   // (2)
                      UseSynchronizationContext = true)]                // (3)

    public MyService : IAsyncContractForClientAndService
    {
        public async Task<TResponse> SendReceiveAsync( TRequest req )
        {
            DoSomethingSynchronous();
            await SomethingAsynchronous(); 
            // await lets other clients call the service here or at any await in
            // subfunctions. Calls from clients execute 'interleaved'.
            return new TResponse( ... );
        }
    }

To run every call on one thread, a System.Threading.SynchronizationContext.Current != null must be present at the moment you Open() the ServiceHost. Using the SynchronizationContext, you need not to care about locks. Atomic, non interruptable code sections stretch roughly from one await to the next. Take care that shared service data is in a consistent state at every await and be aware that successive requests from one client may be responded not in the order they where sent.

On client side, the asynchronous service operation is awaitable:

   var response = await client.Channel.SendReceiveAsync( request );

It is not possible to use out or ref parameters in the operation contract. All response data must be passed by the returned value Task(T).
I use this interface in AsyncWcfLib , it supports a Actor based programming model .

There is a WCF sample in the Async CTP that will show you how to use the async/await model in WCF.

In terms of plans for supporting this model in WCF, you can take a look at the following post:

http://blogs.msdn.com/b/endpoint/archive/2010/11/13/simplified-asynchronous-programming-model-in-wcf-with-async-await.aspx

Hope this helps.

Amadeo

As mentioned by Matt, there is a TaskFactory.FromAsync method that allows you to create a Task from a Begin / End pair. You need to enable asynchronous endpoints when you add your WCF reference, and then you can wrap them up yourself using extension methods.

As mentioned by Amadeo, there is a sample of this in the Async CTP, under the (C# WCF) Stock Quotes directory.

Also in that directory, there is a TaskWsdlImportExtension project. Add a reference to that dll and modify your .config as such:

<configuration>
 <system.serviceModel>
  <client>
   <metadata>
    <wsdlImporters>
     <extension type="TaskWsdlImportExtension.TaskAsyncWsdlImportExtension, TaskWsdlImportExtension" />
    </wsdlImporters>
   </metadata>
  </client>
 </system.serviceModel>
</configuration>

Then you don't have to do your own wrapping at all; the TaskWsdlImportExtension will do it for you.

It is quite common to have asynchronous clients calling a synchronous service.
The following client and service contracts match (a bit magic used behind the scenes):

    [ServiceContract( Namespace="X", Name="TheContract" )]
    public interface IClientContractAsynchronous
    {
        [OperationContract]
        Task<TResponse> SendReceiveAsync( TRequest req );
    }

    [ServiceContract( Namespace="X", Name="TheContract" )]
    public interface IServiceContractSynchronous
    {
        [OperationContract]
        TResponse SendReceive( TRequest req );
    }

The client interface is directly awaitable:

   var response = await client.Channel.SendReceiveAsync( request );

It is not possible to use out or ref parameters in the operaton contract. All response data must be passed in the return value. This actually was a breaking change for me.
I use this interface in AsyncWcfLib , it supports a Actor based programming model .

You rightly point out that async/await are built around methods returning Task and Task (for a great explanation of the working of async/await, see here ). Here's how to generate Task based methods for a WCF service:

  1. Visual Studio 2012 RC has an additional check-box in the "Configure Service Reference" dialog box: "Generate task based operations". While I don't see that option documented in the MSDN , I expect it exists specifically to allow seamless async/await on WCF calls.

  2. For earlier versions, take a look at this post , describing an extension which allows generating Task<> based methods on WCF even with the CTP.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM