2013-06-07 10 views
5

में कभी जवाब नहीं दे रहा है मैं अब एक सप्ताह के लिए async/प्रतीक्षा के साथ संघर्ष कर रहा हूं। कुछ पृष्ठभूमि: नीचे दिया गया कोड एक एमवीसी 4 वेबसाइट प्रोजेक्ट का हिस्सा है। वेबसाइट पर बड़ी संख्या में एपीआई कॉल हो रही हैं। लक्ष्य साइट प्रतिक्रिया को बेहतर बनाने के लिए सिंक्रोनस के बजाय समानांतर में होने वाली उन API कॉल को प्राप्त करना है। अभी सभी एपीआई कॉल एक-दूसरे को अवरुद्ध करते हैं। तो यदि एक पृष्ठ को 4 कॉल की आवश्यकता होती है ... अधिक लोड समय।सी # Async/प्रतीक्षा एमवीसी 4

मैंने सभी एपीआई कॉल के सिंक्रोनस और एसिंक संस्करणों के लिए अलग-अलग तरीकों का निर्माण किया है। मेरी समस्या यह है कि इंतजार कभी जवाब नहीं देता है। मुझे लगता है कि यह this question से संबंधित है। हालांकि, मुझे सच में यकीन नहीं है कि इसे कैसे हल किया जाए। मैंने ConfigureAwait (झूठी) की कोशिश की है, और इससे मेरी मदद नहीं हुई है।

कोड यह रहा:

नियंत्रक में प्रारंभिक कॉल यह इतना की तरह दिखता है:

BaseData bdata = API.GetBaseData().Result; 

मैं उपयोग करने के लिए अच्छा लगेगा यहाँ का इंतजार है, लेकिन यह एक AsyncController बिना एक विकल्प नहीं है, जो हम अनुरोध अनुरोध/प्रतिक्रिया पहुंच के कारण उपयोग नहीं कर सकते हैं। अन्य तरीकों एपीआई वर्ग में हैं:

internal static async Task<BaseData> GetBaseData() { 
    var catTask = GetParentCategoriesAsync(); 
    var yearTask = GetYearsAsync(); 

    await Task.WhenAll(new Task[] { catTask, yearTask }); 

    var bdata = new BaseData { 
     years = await yearTask, 
     cats = await catTask 
    }; 
    return bdata; 
} 

internal static async Task<List<APICategory>> GetParentCategoriesAsync() { 
    try { 
     WebClient wc = new WebClient(); 
     wc.Proxy = null; 

     string url = getAPIPath(); 
     url += "GetFullParentCategories"; 
     url += "?dataType=JSON"; 

     Uri targeturi = new Uri(url); 
     List<APICategory> cats = new List<APICategory>(); 

     var cat_json = await wc.DownloadStringTaskAsync(targeturi); 
     cats = JsonConvert.DeserializeObject<List<APICategory>>(cat_json); 

     return cats; 
    } catch (Exception) { 
     return new List<APICategory>(); 
    } 
} 

internal static async Task<List<double>> GetYearsAsync() { 
    WebClient wc = new WebClient(); 
    wc.Proxy = null; 
    Uri targeturi = new Uri(getAPIPath() + "getyear?dataType=JSON"); 
    var year_json = await wc.DownloadStringTaskAsync(targeturi); 
    List<double> years = JsonConvert.DeserializeObject<List<double>>(year_json); 
    return years; 
} 

जब इन पद्धतियों को बुलाया जाता है, मैं GetYearsAsync() और GetParentCategoriesAsync में breakpoints डाल सकता है()। सबकुछ wc.DownloadStringTaskAsync (targeturi) कमांड तक प्रतीक्षा करता है। वह जगह है जहां बंद हो जाता है।

मैंने सभी कार्यों में ConfigureAwait (जारीOnCapturedContext: false) जोड़ा है, लेकिन इससे मदद नहीं मिली है। मुझे लगता है कि समस्या यह है कि धागे एक ही संदर्भ में नहीं हैं। हालांकि, मैं निश्चित नहीं हूँ। मुझे यकीन है कि, मैं कुछ गलत कर रहा हूँ। मुझे यकीन नहीं है कि क्या। यह या तो है या मैं बस कुछ ऐसा करने की कोशिश कर रहा हूं जो .NET MVC4 के साथ नहीं किया जा सकता है। किसी भी विचार की सराहना की जाएगी।

+5

यदि आप "सभी तरह से एसिंक नहीं कर सकते" तो एसिंक विधियों का उपयोग करने में वास्तव में बहुत अधिक बिंदु नहीं है। यदि आप शीर्ष स्तर पर कार्य पर अवरुद्ध होने जा रहे हैं तो भी आप अपने ऑपरेशन की पूरी अवधि के लिए एक थ्रेड पूल थ्रेड व्यस्त रख रहे हैं। आप पूरे समय गैर-एसिंक विधियों का भी उपयोग कर सकते हैं। – Servy

+0

यदि आप पृष्ठभूमि में लंबे समय से चल रहे संचालन कर रहे हैं, तो आपको एक सेवा की आवश्यकता है, जो HTTP अनुरोध से परे रहता है। –

+3

"जिसे हम अनुरोध/प्रतिक्रिया पहुंच की आवश्यकता के कारण उपयोग नहीं कर सकते हैं" - सुनिश्चित नहीं है कि इसका मतलब क्या है? 'async' कोड अनुरोध और प्रतिक्रिया को ठीक से एक्सेस कर सकता है। –

उत्तर

0

मैं सेवा और स्टीफन क्लेरी की सलाह के संयोजन के बाद समाप्त हुआ। स्टीफन की प्रतिक्रिया के आधार पर, मुझे एहसास हुआ कि जब तक मैंने नियंत्रक में एसिंक्रोनस कॉल करने से पहले मैंने अनुरोध किया था तब तक मैं अनुरोध/प्रतिक्रिया तक पहुंच सकता था।

यदि मैंने एक चर में HttpContext संग्रहीत किया है, तो मैं उस संदर्भ को किसी भी मॉडल/सेवा विधि के पास पास कर सकता हूं जिसके लिए इसकी आवश्यकता होती है। इसने मुझे Servy सुझाए गए सभी तरह से एसिंक जाने की अनुमति दी। उसके बाद, मुझे एसिंक पैटर्न के साथ जो कुछ भी चाहिए था उसके साथ मुझे कोई समस्या नहीं थी।

+2

कम से कम कहने के लिए किसी अन्य चर के लिए एक चर में 'HttpContext' पास करना जो उस तक पहुंच नहीं है, इसकी अनुशंसा नहीं की जाती है। बस 'async' और' await' (बिना 'कॉन्फ़िगरएवाइट' के') का उपयोग करें और आप 'HttpContext.Current' तक पहुंचने में सक्षम होंगे * * और * प्रतीक्षा के बाद बस ठीक है। –

+0

बड़ी समस्या जो मैं शुरुआत में केवल सादे पुराने एसिंक/प्रतीक्षा के साथ चल रहा था वह था कि HttpContext.Current सहायक डेटा में खाली था जिसे कुकी डेटा प्राप्त करने और सेट करने के लिए आवश्यक था। एसिंक और प्रतीक्षा के साथ, HttpContext.Current तक पहुंचने का प्रयास करते समय किए गए किसी भी विधि कॉल ने शून्य संदर्भ त्रुटियों को फेंक दिया होगा। एक चर में HttpContext.Current संग्रहीत करके, मैं इसे चारों ओर पास कर सकता हूं जैसे मैंने अन्य भाषाओं में मॉडलिंग देखा है। एक चर के रूप में इसे संग्रहीत किए बिना, कुकी तर्क बिल्कुल काम नहीं करेगा। मुझे लगता है कि ऐसा कुछ होना है जिसे मैं अभी भी याद कर रहा हूं। – janiukjf

+0

तब यह एक अलग समस्या है। मैं इस सवाल के साथ एक न्यूनतम रेपो पोस्ट करने की सलाह देता हूं कि क्यों 'HttpContext.Current' 'null' है। –

2

समस्या WebClient की वजह से वास्तव में है, जो होगा हमेशा सिंक वापस अनुरोध संदर्भ (जो Result कॉल की वजह से अवरुद्ध है) करने के लिए।

आप HttpClient बजाय उपयोग कर सकते हैं, ConfigureAwait(false) के साथ संयुक्त:

internal static async Task<BaseData> GetBaseDataAsync() { 
    var catTask = GetParentCategoriesAsync(); 
    var yearTask = GetYearsAsync(); 

    await Task.WhenAll(catTask, yearTask).ConfigureAwait(false); 

    var bdata = new BaseData { 
    years = await yearTask, 
    cats = await catTask 
    }; 
    return bdata; 
} 

internal static async Task<List<APICategory>> GetParentCategoriesAsync() { 
    try { 
    var client = new HttpClient(); 

    string url = getAPIPath(); 
    url += "GetFullParentCategories"; 
    url += "?dataType=JSON"; 

    Uri targeturi = new Uri(url); 
    List<APICategory> cats = new List<APICategory>(); 

    var cat_json = await client.GetStringAsync(targeturi).ConfigureAwait(false); 
    cats = JsonConvert.DeserializeObject<List<APICategory>>(cat_json); 

    return cats; 
    } catch (Exception) { 
    return new List<APICategory>(); 
    } 
} 

internal static async Task<List<double>> GetYearsAsync() { 
    var client = new HttpClient(); 
    Uri targeturi = new Uri(getAPIPath() + "getyear?dataType=JSON"); 
    var year_json = await client.GetStringAsync(targeturi).ConfigureAwait(false); 
    List<double> years = JsonConvert.DeserializeObject<List<double>>(year_json); 
    return years; 
} 

है कि आप सक्षम होना चाहिए जैसे इसे कहते हैं:

BaseData bdata = API.GetBaseDataAsync().Result; 

हालांकि, मैं दृढ़ता से सुझाव है कि आप इसे के रूप में फोन जैसे:

BaseData bdata = await API.GetBaseDataAsync(); 

आप पाएंगे कि await के पहले और बाद में दोनों कोड अनुरोध और प्रतिक्रिया संदर्भ को ठीक से एक्सेस कर सकते हैं।