HttpClient में प्रतीक्षा के साथ Async कॉल कभी वापस नहीं आती है


95

मेरे पास एक कॉल है जो मैं एक xaml- आधारित, C#मेट्रो एप्लीकेशन के अंदर 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 कॉल वास्तव में लगभग तुरंत लौटता है (फिडलर के माध्यम से पुष्टि की गई); यह ऐसा है जैसे कि awaitनजरअंदाज कर दिया गया हो और यह बस वहीं लटक गया हो।

इससे पहले कि आप पूछें - हाँ - निजी नेटवर्क क्षमता चालू है।

किसी भी विचार क्यों यह लटका होगा?


1
आप उस asyncतरीके को कैसे कह रहे हैं ? क्या यह अपवाद नहीं है?
18

जवाबों:


136

मेरे प्रश्न के इस उत्तर की जाँच करें जो बहुत समान लगता है।

कोशिश करने के लिए कुछ: ConfigureAwait(false)टास्क द्वारा कॉल पर लौटा GetStreamAsync()। उदाहरण के लिए

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

यह उपयोगी है या नहीं यह इस बात पर निर्भर करता है कि ऊपर दिए गए आपके कोड को कैसे कहा जा रहा है - मेरे मामले में कोड को लटका देने के कारण asyncविधि का उपयोग Task.GetAwaiter().GetResult()करना।

ऐसा इसलिए है क्योंकि GetResult()टास्क पूरा होने तक वर्तमान थ्रेड को ब्लॉक करता है। जब कार्य पूरा हो जाता है तो यह उस थ्रेड संदर्भ को फिर से दर्ज करने का प्रयास करता है जिसमें इसे शुरू किया गया था, लेकिन ऐसा नहीं हो सकता क्योंकि उस संदर्भ में पहले से ही एक थ्रेड है, जिसे कॉल GetResult()... डेडलॉक द्वारा अवरुद्ध किया गया है !

यह MSDN पोस्ट कुछ विस्तार से बताती है कि कैसे .NET समानांतर थ्रेड को सिंक्रोनाइज़ करता है - और मेरे अपने प्रश्न का उत्तर कुछ सर्वोत्तम अभ्यास देता है।


12
धन्यवाद, लगभग इसे देखने से पहले async / प्रतीक्षा पर छोड़ दिया।
डेन

4
मैं भी! यह सामान बेहतर दस्तावेज क्यों नहीं है? धन्यवाद फिर से
एवरहोम यिसरेल

1
क्या ऐसा होने वाला है अगर यह न तो UI संदर्भ और ASP.NET संदर्भ है?
मशिनारियम

1
बहुत बढ़िया जवाब! लेकिन मुझे भ्रम है कि अब तक HttpClient का उपयोग करते समय मेरे पास केवल यही मुद्दा क्यों है, ऐसा लगता है कि HttpClient के भीतर अंतर्निहित कार्यान्वयन सही तरीके से लागू नहीं हुआ है। अन्य वर्कअराउंड में मैंने वर्तमान थ्रेड को STA के रूप में स्थापित करना शामिल किया है जो कि मदद करता है लेकिन वास्तव में अप्रत्यक्ष है विशेष रूप से जब आप एक 3rd पार्टी असेंबली का उपयोग कर रहे हैं और यह नहीं जानते हैं कि हुड के तहत कुछ कॉल एक प्रतिक्रिया के लिए निश्चित रूप से प्रतीक्षा करने जा रही है। कभी नहीं मिलने वाला है। मेरे मामले में dll इन-हाउस था, इसलिए हम कॉन्फिगअवाइट को सक्षम कर रहे थे ... लेकिन इसे सबसे निचले स्तर पर HttpClient ओबज के लिए किया जाना था।
क्रिस स्कॉलर

2
@ChrisSchaller stackoverflow.com/a/10351400/174735 पर पूरा उत्तर पढ़ना सुनिश्चित करें , जो इस मुद्दे को पूरी तरह से समझाता है।
बेंजामिन फॉक्स

5

बस एक हेड अप - यदि आप ASP.NET कंट्रोलर में शीर्ष स्तर पर वेट को मिस करते हैं, और आप रिस्पॉन्स के परिणामस्वरूप टास्क को वापस कर देते हैं, तो यह वास्तव में बिना किसी त्रुटि के नेस्टेड वेट कॉल (s) में हैंग हो जाता है। एक मूर्खतापूर्ण गलती, लेकिन क्या मैंने इस पोस्ट को देखा है यह शायद मुझे कुछ अजीब के लिए कोड के माध्यम से जाँच करने से बचा सकता है।


0

डिस्क्लेमर: मुझे कन्फिगरवाइट () समाधान पसंद नहीं है क्योंकि मुझे यह गैर-सहज और याद रखने में कठिन लगता है। इसके बजाय मैं टास्क में गैर प्रतीक्षित विधि कॉल को लपेटने के निष्कर्ष पर आया था। () (> = myAsyncMethodNotUsingAwait ())। यह 100% काम करता है, लेकिन सिर्फ एक दौड़ की स्थिति हो सकती है !? मुझे यकीन नहीं है कि ईमानदार होने के लिए क्या हो रहा है। यह निष्कर्ष गलत हो सकता है और मैं अपने StackOverflow के बिंदुओं को जोखिम में डालने के लिए यहाँ से जोखिम लेता हूँ: -P कृपया उन्हें पढ़ें!

मुझे सिर्फ समस्या के रूप में वर्णित और यहाँ अधिक जानकारी मिली ।

कथन है: "आप एक अतुल्यकालिक विधि नहीं कह सकते हैं"

await asyncmethod2()

एक ऐसी विधि से जो ब्लॉक होती है

myAsyncMethod().Result

मेरे मामले में मैं कॉलिंग विधि नहीं बदल सकता था और यह async नहीं था। लेकिन मुझे वास्तव में परिणाम की परवाह नहीं थी। जैसा कि मुझे याद है कि यह .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);
}

मेरे मामले में मुझे कॉलिंग नॉन-असिंक विधि में परिणाम के बारे में परवाह नहीं थी, लेकिन मुझे लगता है कि इस उपयोग के मामले में काफी आम है। आप परिणाम को कॉल करने के लिए async विधि का उपयोग कर सकते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.