114 votes

Un appel asynchrone avec await dans HttpClient ne revient jamais

J'ai un appel que je fais depuis l'intérieur d'une base xaml, C# sur le PC Win8 ; cet appel appelle simplement un service web et renvoie des données 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);

Il est accroché à la await mais le http revient en fait presque immédiatement (confirmé par fiddler) ; c'est comme si l'appel await est ignoré et il ne bouge pas.

Avant de demander - OUI - la fonction de réseau privé est activée.

Une idée de la raison de ce blocage ?

168voto

deadalus.ai Points 567

Vérifiez cette réponse à ma question qui semble être très similaire.

Quelque chose à essayer : appeler ConfigureAwait(false) sur la tâche renvoyée par GetStreamAsync() . Par exemple

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

L'utilité de cette fonction dépend de la manière dont le code ci-dessus est appelé - dans mon cas, il s'agit de l'appel de la fonction async méthode utilisant Task.GetAwaiter().GetResult() a provoqué le blocage du code.

Cela s'explique par le fait que GetResult() bloque le fil d'exécution actuel jusqu'à ce que la tâche soit terminée. Lorsque la tâche se termine, elle tente de réintégrer le contexte de threads dans lequel elle a été lancée, mais elle ne peut pas le faire parce qu'il y a déjà un thread dans ce contexte, qui est bloqué par l'appel à la fonction GetResult() ... impasse !

Cet article de MSDN explique en détail comment .NET synchronise les threads parallèles - et la réponse donnée à ma propre question donne quelques bonnes pratiques.

10voto

bozzle Points 936

Juste une info - si vous manquez le await au niveau supérieur dans un contrôleur ASP.NET, et que vous renvoyez la tâche au lieu du résultat en tant que réponse, il se bloque dans les appels await imbriqués sans aucune erreur. C'est une erreur stupide, mais si j'avais vu ce message, j'aurais pu gagner du temps en vérifiant le code pour trouver quelque chose d'étrange.

0voto

yourmother Points 157

Disclaimer : Je n'aime pas la solution ConfigureAwait() car je la trouve non-intuitive et difficile à retenir. A la place, je suis arrivé à la conclusion d'envelopper les appels de méthodes non attendues dans Task.Run(() => myAsyncMethodNotUsingAwait()). Cela semble fonctionner à 100%, mais il pourrait s'agir d'une condition de course ? Pour être honnête, je ne suis pas sûr de ce qui se passe. Cette conclusion pourrait être erronée et je risque mes points StackOverflow ici pour espérer apprendre des commentaires :-P. S'il vous plaît, lisez-les !

J'ai eu le même problème que celui décrit et j'ai trouvé plus d'informations. aquí .

La déclaration est : "vous ne pouvez pas appeler une méthode asynchrone".

await asyncmethod2()

d'une méthode qui bloque

myAsyncMethod().Result

Dans mon cas, je ne pouvais pas changer la méthode d'appel et ce n'était pas asynchrone. Mais je ne me souciais pas vraiment du résultat. Si je me souviens bien, cela ne fonctionnait pas non plus de supprimer le .Result et d'avoir le await manquant.

Alors j'ai fait ça :

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

Dans mon cas, je ne me suis pas soucié du résultat dans l'appel de la méthode non-asynchrone, mais je suppose que c'est assez courant dans ce cas d'utilisation. Vous pouvez utiliser le résultat dans l'appel de la méthode asynchrone.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X