2012-06-29 9 views
5

के माध्यम से कार्य को निष्पादित करना मैं निर्भरता इंजेक्शन के साथ AsyncController को मिश्रित करने का प्रयास कर रहा हूं। प्रश्न में एमवीसी ऐप एसिंक वेब सेवा कॉल के माध्यम से लगभग सभी डेटा प्राप्त करता है। हम टीपीएल से कार्य में एसिंक काम को लपेट रहे हैं, और इन कार्यों को पूरा करते समय नियंत्रक के AsyncManager को सूचित करते हैं।एएसपी.NET सिंक्रनाइज़ेशन संदर्भ के माध्यम से सुरक्षित रूप से और AsyncManager.Sync

कभी-कभी हमें इन कार्यों की निरंतरता में HttpContext को स्पर्श करना होता है - एक कुकी जोड़ना, जो भी हो। Using an Asynchronous Controller in ASP.NET MVC के अनुसार ऐसा करने का सही तरीका AsyncManager.Sync विधि को कॉल करना है। यह एएसपी.NET थ्रेड संदर्भ को प्रचारित करेगा, जिसमें HttpContext, वर्तमान थ्रेड में, कॉलबैक निष्पादित करें, फिर पिछले संदर्भ को पुनर्स्थापित करें।

हालांकि, उस लेख में यह भी कहते हैं:

एक धागा ASP.NET के नियंत्रण के तहत पहले से ही है कि व्यवहार अपरिभाषित है से सिंक() कॉलिंग।

यह कोई समस्या नहीं है यदि आप नियंत्रक में अपना पूरा काम करते हैं, क्योंकि आप आम तौर पर जानते हैं कि निरंतरता में आपको क्या थ्रेड होना चाहिए। लेकिन मैं जो करने की कोशिश कर रहा हूं वह हमारे एसिंक डेटा एक्सेस और हमारे एसिंक नियंत्रकों के बीच एक मध्यम परत बनाता है। तो ये भी async हैं। सब कुछ एक डी कंटेनर द्वारा तारित किया जाता है।

तो पहले की तरह, कॉल श्रृंखला में कुछ घटकों को "वर्तमान" HttpContext के साथ काम करने की आवश्यकता होगी। उदाहरण के लिए, लॉगऑन के बाद हम "सत्र" टोकन को स्टोर करना चाहते हैं, हम एक सिंगल-साइन-ऑन सेवा से वापस आते हैं। उस चीज़ के लिए अमूर्त जो ISessionStore है। कुकी कुकीशन के बारे में सोचें जो प्रतिक्रिया पर एक कुकी रखता है, या अनुरोध से कुकी पकड़ लेता है।

दो समस्याओं मैं इस के साथ देख सकते हैं:

  1. घटकों AsyncManager लिए पहुँच नहीं है या यहां तक ​​कि वे एक नियंत्रक के भीतर इस्तेमाल किया जा रहा हो पता है।
  2. घटक नहीं जानते कि उन्हें किस धागे से बुलाया जा रहा है, और इसलिए AsyncManager.Sync या कोई समकक्ष सैद्धांतिक रूप से समस्याग्रस्त है।

# 1 का समाधान करने के लिए, मैं मूल रूप से एक वस्तु है कि अनुरोध की शुरुआत में TaskScheduler.FromCurrentSynchronizationContext() पकड़ लेता है इंजेक्शन रहा हूँ, और एक कार्रवाई आह्वान कर सकते हैं के माध्यम से एक टास्क, कि अनुसूचक के साथ शुरू किया HttpContextBase लेने एक तर्क के रूप।

है यही कारण है कि, मेरे घटकों से, मैं करने के लिए कुछ इसी तरह कॉल कर सकते हैं:

MySyncObject.Sync(httpContext => /* Add a cookie or something else */); 

मैं अभी तक इस के साथ कोई समस्या नहीं देखा है, लेकिन मैं इस समस्या # 2 के बारे में चिंतित हूँ। मैंने प्रतिबिंबक में AsyncManager और SynchronizationContextTaskScheduler दोनों को देखा है, और वे एएसपी.NET SynchronizationContext पर कॉलबैक निष्पादित करने के समान ही काम करते हैं। और वह मुझे डराता है :)

मुझे कुछ उम्मीद थी जब मैंने देखा कि कार्य शेड्यूलर कार्यान्वयन सिंक्रनाइज़ेशन संदर्भ के माध्यम से सीधे इनलाइन करने के बजाय प्रत्यक्ष रूप से आ जाएगा। लेकिन दुर्भाग्यवश, यह सामान्य Task.Start(scheduler) कोड-पथ के माध्यम से नहीं प्रतीत होता है। इसके बजाय, कार्यों को अन्य परिस्थितियों में रेखांकित किया जा सकता है, जैसे कि वे शुरू होने से पहले इंतजार कर रहे हैं।

तो मेरी प्रश्न हैं:

  1. Am मैं इस दृष्टिकोण के साथ यहाँ मुसीबत में चलाने के लिए जा रहे हैं?
  2. क्या कोई बेहतर तरीका है?
  3. क्या इस परिदृश्य में सिंक्रनाइज़ करने की उपयोगिता केवल गैर-थ्रेड-सुरक्षित HttpContext तक पहुंच को क्रमबद्ध करने के लिए है? यानी मैं इसके बजाय थ्रेड-सुरक्षित HttpContextBase wrapper (ick) से दूर हो सकता हूं?
+0

यदि आप 'टास्क.स्टार्ट (शेड्यूलर) 'का उपयोग करते हैं, तो यह अभी भी संभव है कि यह रेखांकित हो जाएगा, अगर आप इसे तुरंत प्रतीक्षा करें()'। बेशक, हम मल्टीथ्रेडिंग के बारे में बात कर रहे हैं, इसलिए यह संभव है कि "तुरंत" "जल्दी से पर्याप्त" नहीं होगा। – svick

+0

हम्म मुझे यह नहीं दिख रहा है। बेशक, मेरे पास अभी .NET 4.5 स्थापित है, तो कौन जानता है? :) –

उत्तर

1

थ्रेड-स्थानीय स्टेटिक्स पर निर्भरता शायद ही कभी एक अच्छा विचार है। जबकि HttpContext.Current उस तंत्र पर निर्भर करता है और यह वर्षों से काम करता है, अब हम एसिंक जा रहे हैं, यह दृष्टिकोण तेजी से खराब हो रहा है। इस स्थैतिक के मूल्य को स्थानीय चर के रूप में कैप्चर करना और अपने एसिंक काम के साथ पास करना बेहतर है ताकि आपके पास हमेशा यह हो। तो, उदाहरण के लिए:

public async Task<ActionResult> MyAction() { 
    var context = HttpContext.Current; 
    await Task.Yield(); 
    var item = context.Items["something"]; 
    await Task.Yield(); 
    return new EmptyResult(); 
} 

या और भी बेहतर, HttpContext.Current पूरी तरह से बचने के लिए यदि आप MVC में कर रहे हैं:

public async Task<ActionResult> MyAction() { 
    await Task.Yield(); 
    var item = this.HttpContext.Items["something"]; 
    await Task.Yield(); 
    return new EmptyResult(); 
} 

बेशक, अपने मिडलवेयर व्यापार तर्क विशेष रूप से HttpContext या कुछ और पर नहीं भरोसा किया जाना चाहिए एएसपी.नेट पुस्तकालयों में। इसलिए कुकीज सेट करने के लिए अपने मिडलवेयर कॉल को अपने कंट्रोलर (कॉलबैक, इंटरफेस इत्यादि के माध्यम से) पर वापस कॉल करना होगा, फिर आपके पास उस संदर्भ तक पहुंचने के लिए उपयोग करने के लिए this.HttpContext उपलब्ध होगा।