Mam połączenie, które C#
wykonuję z poziomu aplikacji Metro opartej na XAML na Win8 CP; wywołanie to po prostu trafia do usługi sieciowej i zwraca dane 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);
Zawiesza się w miejscu, await
ale wywołanie http w rzeczywistości powraca prawie natychmiast (potwierdzone przez skrzypek); to jest tak, jakby await
był ignorowany i po prostu wisi tam.
Zanim zapytasz - TAK - funkcja Private Network jest włączona.
Jakieś pomysły, dlaczego to się zawiesi?
c#
asynchronous
async-await
dotnet-httpclient
keithwarren7
źródło
źródło
async
metodę? Czy to nie stanowi wyjątku?Odpowiedzi:
Sprawdź tę odpowiedź na moje pytanie, które wydaje się być bardzo podobne.
Coś do wypróbowania: zadzwoń
ConfigureAwait(false)
do zadania zwróconego przezGetStreamAsync()
. Na przykładvar result = await httpClient.GetStreamAsync("weeklyplan") .ConfigureAwait(continueOnCapturedContext:false);
To, czy jest to przydatne, zależy od tego, jak wywoływany jest powyższy kod - w moim przypadku wywołanie
async
metody usingTask.GetAwaiter().GetResult()
spowodowało zawieszenie się kodu.Dzieje się tak, ponieważ
GetResult()
blokuje bieżący wątek do momentu zakończenia zadania. Po zakończeniu zadania próbuje ponownie wejść do kontekstu wątku, w którym zostało uruchomione, ale nie może, ponieważ w tym kontekście istnieje już wątek, który jest blokowany przez wywołanieGetResult()
... zakleszczenia!W tym poście w witrynie MSDN szczegółowo omówiono, w jaki sposób .NET synchronizuje równoległe wątki - a odpowiedź udzielona na moje własne pytanie zawiera kilka najlepszych praktyk.
źródło
Tylko ostrzeżenie - jeśli przegapisz oczekiwanie na najwyższym poziomie w kontrolerze ASP.NET i zwrócisz zadanie zamiast wyniku jako odpowiedź, w rzeczywistości po prostu zawiesza się w zagnieżdżonych wywołaniach oczekiwania bez błędów. Głupi błąd, ale gdybym zobaczył ten post, zaoszczędziłoby mi to trochę czasu na sprawdzaniu kodu pod kątem czegoś dziwnego.
źródło
Zastrzeżenie: nie podoba mi się rozwiązanie ConfigureAwait (), ponieważ wydaje mi się nieintuicyjne i trudne do zapamiętania. Zamiast tego doszedłem do wniosku, że nieoczekiwane wywołania metod zawijają w Task.Run (() => myAsyncMethodNotUsingAwait ()). Wydaje się, że działa to w 100%, ale może to być tylko stan wyścigu !? Nie jestem pewien, co się dzieje, szczerze mówiąc. Ten wniosek może być błędny i ryzykuję, że moje punkty StackOverflow tutaj, mam nadzieję, wyciągną wnioski z komentarzy :-P. Przeczytaj je!
Właśnie miałem problem zgodnie z opisem i znalazłem więcej informacji tutaj .
Instrukcja brzmi: „nie można wywołać metody asynchronicznej”
await asyncmethod2()
z metody, która blokuje
W moim przypadku nie mogłem zmienić metody wywoływania i nie było to asynchroniczne. Ale tak naprawdę nie dbałem o wynik. O ile pamiętam, nie działało również usuwanie .Result i brakowało czekania.
Więc zrobiłem to:
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); }
W moim przypadku nie przejmowałem się wynikiem w wywołaniu metody innej niż asynchroniczna, ale myślę, że jest to dość powszechne w tym przypadku użycia. Możesz użyć wyniku w wywołującej metodzie asynchronicznej.
źródło