HttpClient'te await ile zaman uyumsuz çağrı asla dönmez


96

C#Win8 CP'de xaml tabanlı bir metro uygulamasının içinden yaptığım bir çağrı var ; bu çağrı yalnızca bir web hizmetine gider ve JSON verilerini döndürür.

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

Beklemede kalıyor, awaitancak http çağrısı aslında hemen geri dönüyor (fiddler aracılığıyla onaylandı); sanki awaitgörmezden geliniyor ve orada asılı duruyor.

Siz sormadan önce - EVET - Özel Ağ özelliği açık.

Bunun neden asıldığına dair bir fikriniz var mı?


1
Bu asyncyöntemi nasıl adlandırıyorsun ? Bir istisna oluşturmaz mı?
svick

Yanıtlar:


138

Soruma çok benzeyen bu cevaba bir göz atın .

Denenecek bir şey: ConfigureAwait(false)tarafından döndürülen Görevi arayın GetStreamAsync(). Örneğin

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

Bunun yararlı olup olmadığı yukarıdaki kodunuzun nasıl çağrıldığına bağlıdır - benim durumumda asyncyöntemi kullanarak yöntemi çağırmak Task.GetAwaiter().GetResult()kodun takılmasına neden oldu.

Bunun nedeni GetResult(), Görev tamamlanana kadar geçerli iş parçacığını engellemesidir. Görev tamamlandığında, başlatıldığı iş parçacığı bağlamına yeniden girmeye çalışır, ancak bu bağlamda zaten bir iş parçacığı olduğu için giremez, bu da GetResult()... deadlock!

Bu MSDN gönderisi , .NET'in paralel iş parçacıklarını nasıl senkronize ettiğine dair biraz ayrıntıya giriyor - ve kendi soruma verilen yanıt bazı en iyi uygulamaları sağlıyor.


12
Teşekkürler, bunu görmeden önce neredeyse eşzamansız / beklemekten vazgeçtim.
Den

4
Ben de! Bu şeyler neden daha iyi belgelenmiyor? Tekrar teşekkürler
Avrohom Yisroel

1
Ne UI bağlamında ne de ASP.NET bağlamında değilse gerçekleşecek mi?
machinarium

1
Harika cevap! Ancak şu ana kadar neden sadece HttpClient kullanırken bu sorunu yaşadığımı kafam karıştı, HttpClient içindeki temel uygulama doğru şekilde uygulanmamış gibi görünüyor. Bulduğum diğer geçici çözümler, mevcut iş parçacığını STA olarak ayarlamayı içerir, bu da yardımcı olur, ancak özellikle 3. taraf bir montaj kullanırken gerçekten dolaylıdır ve kaputun altında bazı aramaların kesinlikle bir yanıt bekleyeceğini bilmiyorsunuz. asla elde edemeyecek. Benim durumumda dll şirket içindeydi, bu yüzden ConfigureAwait'i başardık ... ama HttpClient nesnesine en düşük seviyede yapılması gerekiyordu.
Chris Schaller

2
@ChrisSchaller Sorunun tamamını tamamen açıklayan stackoverflow.com/a/10351400/174735 adresindeki tam cevabı okuduğunuzdan emin olun .
Benjamin Fox

5

Sadece bir uyarı - bir ASP.NET denetleyicisinde en üst düzeydeki beklemeyi kaçırırsanız ve görevi sonuç yerine yanıt olarak döndürürseniz, aslında iç içe geçmiş bekleme çağrılarında hata olmadan askıda kalır. Aptalca bir hata, ancak bu yazıyı görmüş olsaydım, tuhaf bir şey için kodu kontrol etmeme biraz zaman kazandırabilirdi.


0

Sorumluluk reddi: ConfigureAwait () çözümünü sevmiyorum çünkü sezgisel olmadığını ve hatırlaması zor buluyorum. Bunun yerine, Task.Run (() => myAsyncMethodNotUsingAwait ()) içinde beklenmeyen yöntem çağrılarını sarmalama sonucuna vardım. Bu% 100 çalışıyor gibi görünüyor, ancak sadece bir yarış durumu olabilir !? Dürüst olmak gerekirse neler olup bittiğinden pek emin değilim. Bu sonuç yanlış olabilir ve umarım yorumlardan öğrenmek için StackOverflow puanlarımı riske atarım :-P. Lütfen bunları okuyun!

Sorunu açıklandığı gibi yaşadım ve burada daha fazla bilgi buldum .

İfade şudur: "zaman uyumsuz bir yöntemi çağıramazsınız"

await asyncmethod2()

engelleyen bir yöntemden

myAsyncMethod().Result

Benim durumumda arama yöntemini değiştiremedim ve eşzamansız değildi. Ama aslında sonucu umursamadım. Hatırladığım kadarıyla, .Result'u kaldırmaya çalışmadı ve bekleme eksikliğine sahipti.

Ben de bunu yaptım:

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

Benim durumumda, eşzamansız olmayan yöntemi çağırmanın sonucunu önemsemedim, ancak bu kullanım durumunda bu oldukça yaygın olduğunu tahmin ediyorum. Sonucu async yöntemini çağırmada kullanabilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.