2014-04-17 5 views
0

Давайте скажем, что im в приложении ASP.NET, WCF или веб-API, часть этого приложения, связанная с контактом с третьей стороной по пути. Id нравится делать это асинхронно или, скорее, не блокировать, чтобы пул потоков не истощался. Однако я не хочу менять весь свой код в сервисе только бит, который делает веб-вызов.Как сделать асинхронные веб-вызовы изнутри asp.net

Вот код, я написал:

public string GetSomeData() 
    { 
     Task<string> stuff = CallApiAsync(); 

     return stuff.result; //does this block here? 

    } 

    private async Task<string> CallApiasync() 
    { 
     using (var httpClient = new HttpClient()) 
     { 
      string response = await httpClient.GetStringAsync(Util.EndPoint).ConfigureAwait(false); 

      return response; 
     } 

    } 

Я думал, что идея была следующей, но пожалуйста исправить любые неправильные представления.

Вызывающий вызов CallApi может вызывать метод, и когда он попадает в ожидании, создается задача, которая представляет собой некоторую работу, выполняемую асинхронно, но это займет некоторое время. В этот момент поток достигает ожиданий, возвращаясь к пулу потоков, чтобы сделать что-то еще, т.е. обрабатывать другой запрос. После того, как Задача завершится, линия ожидания просыпается, и код продолжается оттуда, как если бы он был синхронным.

Если это так, почему мне нужно вернуть задачу из моего apimethod. Кажется, что вызывающий вызов вызывает stuff.Result, который подразумевает, что задача может не завершиться, и результат вызова может блокироваться? Заметьте, я не хочу, чтобы вызывающий метод был асинхронным, а затем метод, который вызывает это, должен быть асинхронным и т. Д.

Что представляет собой мероприятие здесь, в моем коде?

Другой вопрос, почему мне нужно установить configureAwait в false? иначе все висит.

ответ

6

Id нравится делать это асинхронно или, скорее, не блокировать, чтобы пул потоков не истощался.Однако я не хочу менять весь свой код в сервисе только бит, который делает веб-вызов.

Это невозможно. Чтобы быть по-настоящему асинхронным, вы должны разрешить async «расти» через код, насколько это необходимо. То, что вы пытаетесь сделать, это блокировать асинхронный вызов, который не даст вам никакой пользы (вы освобождаете поток, используя async, но затем вы поворачиваете и потребляете поток, используя Result).

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

Не совсем. Когда метод async попадает в await, он возвращает незаполненный Taskсвоему вызывающему абоненту. Если вызывающему абоненту, в свою очередь, await s, что задача, то она возвращает неполную Task к его абонента и т.д. Когда среда выполнения ASP.NET получает неполную Task от вашего метода действий/обслуживания/что угодно, затем он освобождает поток в пуле потоков.

Итак, вам нужно пойти «async полностью», чтобы увидеть реальную выгоду от async.

У меня есть async intro на моем блоге, если вы хотите более нежное введение, а также статью MSDN на async best practices (один из которых: async). У меня также есть сообщение в блоге, которое описывает deadlock you were seeing.

+0

Хороший ответ спасибо Я теперь понимаю, где я был неправ. Я не уверен, что async - это все, что полезно вне простых демонстрационных приложений. В моем случае у нас есть фрагмент кода библиотеки, который делает веб-звонок, но перед этим у нас есть тонна бизнес-логики. Это означает, что async/await и Task будет протекать по всему моему коду. Все, что я хочу, чтобы это произошло не блокирующим образом! какой мой лучший вариант или нет бесплатного обеда, как говорится –

+0

Ваш лучший вариант - обнять 'async'. Не рассматривайте его как * заражающий * ваш код; скорее, 'async' просто покажет вам, какие части вашего кода естественно асинхронны. –

1

Компилятор обрабатывает много волшебства за шаблоном асинхронизации для вас, но синтаксически, вы должны сказать ему, что вы хотите, предоставив прототип метода, который гласит: «Хорошо, это асинхронная операция, которая может ждать ».

Чтобы это произошло, ваш метод должен вернуть Task или Task<T>. Любая задача может быть ожидаемой.

Вы должны быть ОЧЕНЬ осторожны при использовании .Result и .Wait(), поскольку они могут блокироваться в некоторых очень неожиданных обстоятельствах, так как среда выполнения может решить выполнить ваш метод синхронно.

Вы должны сказать: wait CallApiAsync();

или, на самом деле воспользоваться этим:

Task stuff = CallApiAsync(); 

//More code that can happen independetly of "stuff" 

await stuff; 

Для того, чтобы сделать это, ваш GetSomeData() функция также должна быть помечена как в асинхронном, но он не должен, сам по себе, возвращать Задача.

Закончено копия рабочей версии асинхронной ваш код:

строка общественной асинхронной GetSomeData() { Задача вещи = CallApiAsync();

return await stuff; 

} 

private async Task<string> CallApiasync() 
{ 
    using (var httpClient = new HttpClient()) 
    { 
     string response = await httpClient.GetStringAsync(Util.EndPoint).ConfigureAwait(false); 

     return response; 
    } 

} 

Честно говоря, если это все, что функция CallApiAsync никогда не собирается делать, вы можете также встраивать его, хотя.

Смежные вопросы