Асинхронный вызов с ожиданием в HttpClient никогда не возвращается - PullRequest
86 голосов
/ 27 марта 2012

Я звоню из xaml, C# metro-приложения на Win8 CP;этот вызов просто обращается к веб-службе и возвращает данные JSON.

HttpMessageHandler handler = new HttpClientHandler();

HttpClient httpClient = new HttpClient(handler);
httpClient.BaseAddress = new Uri("http://192.168.1.101/api/");

var result = await httpClient.GetStreamAsync("weeklyplan");
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(WeeklyPlanData[]));
return (WeeklyPlanData[])ser.ReadObject(result);

Он висит на await, но вызов http фактически возвращается почти немедленно (подтверждается через Fiddler);это как если бы await игнорировалось и просто зависало там.

Прежде чем вы спросите - ДА - функция частной сети включена.

Любые идеипочему это будет зависать?

Ответы [ 3 ]

120 голосов
/ 29 апреля 2012

Посмотрите этот ответ на мой вопрос, который кажется очень похожим.

Что-то попробуйте: позвоните ConfigureAwait(false) на Задачу, возвращенную GetStreamAsync().Например,

var result = await httpClient.GetStreamAsync("weeklyplan")
                             .ConfigureAwait(continueOnCapturedContext:false);

. Полезно это или нет, зависит от того, как вызывается ваш код выше - в моем случае вызов метода async с использованием Task.GetAwaiter().GetResult() привел к зависанию кода.

Это связано с тем, что GetResult() блокирует текущий поток до завершения Задачи.Когда задача завершается, она пытается повторно войти в контекст потока, в котором она была запущена, но не может, потому что в этом контексте уже есть поток, который заблокирован вызовом GetResult() ... deadlock!

В этом сообщении MSDN подробно рассказывается о том, как .NET синхронизирует параллельные потоки - и ответ на мой собственный вопрос дает некоторые рекомендации.

1 голос
/ 04 июля 2019

Просто наперед - если вы пропустили ожидание на верхнем уровне в контроллере ASP.NET, и вы возвращаете задачу, а не результат в качестве ответа, она фактически просто зависает во вложенных вызовах ожидания сошибок нет.Глупая ошибка, но если бы я увидел этот пост, он мог бы сэкономить мне время на проверку кода на предмет чего-то странного.

0 голосов
/ 02 апреля 2019

Отказ от ответственности: мне не нравится решение ConfigureAwait (), потому что я нахожу его не интуитивным и трудно запоминающимся.Вместо этого я пришел к выводу обернуть нежелательные вызовы методов в Task.Run (() => myAsyncMethodNotUsingAwait ()).Кажется, это работает на 100%, но может быть просто условием гонки !?Я не уверен, что происходит, если честно.Этот вывод может быть неправильным, и я рискую своими очками StackOverflow, чтобы, надеюсь, извлечь уроки из комментариев :-P.Пожалуйста, прочитайте их!

У меня просто была проблема, как описано, и я нашел дополнительную информацию здесь .

Заявление: «Вы не можете вызвать асинхронный метод»

await asyncmethod2()

из метода, который блокирует

myAsyncMethod().Result

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

Итак, я сделал это:

public void Configure()
{
    var data = "my data";
    Task.Run(() => NotifyApi(data));
}

private async Task NotifyApi(bool data)
{
    var toSend = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");
    await client.PostAsync("http://...", data);
}

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

...