Async CTP - Как я могу использовать async/await для вызова службы wcf?

Если я вызову метод службы WCF, я бы сделал что-то вроде этого:

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

Как я могу сделать то же самое с помощью нового async ctp? Наверное, мне нужно что-то вроде proxy.DoSomethingTaskAsync или proxy.DoSomethingAsync().ToTask()? Вызов веб-службы должен вернуть Task<T>, чтобы использовать ключевое слово await, но как

Ответы

Ответ 1

В CTP существуют методы factory, которые выполняют работу по превращению регулярных APM-функций (Begin/End) в те, которые совместимы с новым ключевым словом async, например:

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);

Итак, в вашем случае вы можете сделать эквивалент, а затем вы будете называть его так:

async proxy.DoSomethingTaskAsync()

Смотрите этот поток в группе обсуждения CTP для получения дополнительной информации

Ответ 2

Асинхронный сервис с использованием async-ожидания очень чувствителен, поскольку он может чередовать многие вызовы клиентов и выполнять их параллельно (2). Несмотря на это, служба может работать полностью поточно-защищенной в одном потоке (3) и может быть однопользовательской службой (1) или объектом службы, созданной инфраструктурой для сеанса или только для вызова.

При внедрении службы обратите внимание на 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( ... );
        }
    }

Чтобы запускать каждый вызов в одном потоке, в момент открытия() ServiceHost должен присутствовать System.Threading.SynchronizationContext.Current!= null. Используя SynchronizationContext, вам не нужно заботиться о блокировках. Атомные, не прерываемые разделы кода растягиваются примерно от одного ожидания до следующего. Позаботьтесь о том, чтобы общие данные службы находились в согласованном состоянии при каждом ожидании, и имейте в виду, что последовательные запросы от одного клиента могут отвечать не в том порядке, в котором они были отправлены.

С клиентской стороны ожидание работы асинхронной службы:

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

Невозможно использовать или отредактировать параметры в контракте операции. Все данные ответа должны быть переданы возвращаемым значением Task (T).
Я использую этот интерфейс в AsyncWcfLib, он поддерживает модель программирования на основе актера.

Ответ 3

В Async CTP есть образец WCF, который покажет вам, как использовать модель async/wait в WCF.

С точки зрения планов поддержки этой модели в WCF вы можете взглянуть на следующее сообщение:

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

Надеюсь, что это поможет.

Амадео

Ответ 4

Как упоминалось Мэттом, существует метод TaskFactory.FromAsync, который позволяет вам создать Task из пары Begin/End. Вам нужно включить асинхронные конечные точки, когда вы добавите ссылку на WCF, а затем вы можете их обернуть, используя методы расширения.

Как упоминалось Amadeo, в этом примере есть пример этого в Async CTP, в каталоге (C# WCF) Stock Quotes.

Также в этом каталоге есть проект TaskWsdlImportExtension. Добавьте ссылку на эту DLL и измените свой .config как таковой:

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

Тогда вам не нужно делать свою собственную упаковку вообще; TaskWsdlImportExtension сделает это за вас.

Ответ 5

Чаще всего есть асинхронные клиенты, вызывающие синхронный сервис.
Следующие клиентские и служебные контракты соответствуют (бит-магия используется за кулисами):

    [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 );
    }

Клиентский интерфейс прямо ждет:

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

Невозможно использовать или отредактировать параметры в операционном контракте. Все данные ответа должны быть переданы в возвращаемом значении. На самом деле это было для меня изменением.
Я использую этот интерфейс в AsyncWcfLib, он поддерживает модель программирования на основе актера.

Ответ 6

Вы справедливо отметили, что async/await построены вокруг методов, возвращающих Task and Task (для отличного объяснения работы async/await, см. здесь). Здесь, как создавать методы на основе задачи для службы WCF:

  • В Visual Studio 2012 RC есть дополнительный флажок в диалоговом окне "Настройка служебной ссылки": "Генерировать операции на основе задач". Хотя я не вижу этот параметр, зарегистрированный в MSDN, я ожидаю, что он существует специально для разрешения асинхронного/ожидающего вызовов WCF.

  • Для более ранних версий ознакомьтесь с этим сообщением, описывающим расширение, которое позволяет создавать методы на основе Task < > на WCF даже с CTP.