2013-02-15 14 views
7

मेरे पास एमवीसी 4 एपीआई REST एक नए थ्रेड में एक प्रक्रिया लॉन्च करने का प्रयास कर रहा है। मैं फ्रेमवर्क 4.5 के साथ काम कर रहा हूं और सिंक का उपयोग करने और क्लॉज्यूल का इंतजार करने की कोशिश कर रहा हूं।एमवीसी 4 वेबएपीआई प्रक्रिया लॉन्चर

मेरे कोड लगता है:

[AcceptVerbs("POST")] 
public HttpResponseMessage Launch(string id) 
{ 
    runProcessAsync(id); // 1               

    return Request.CreateResponse(HttpStatusCode.Accepted); // 2 
} 

protected async void runProcessAsync(string id) 
{ 
    int exitcode = await runProcess(id); // 3 
    string exitcodesz = string.Format("exitcode: {0}", exitcode); // 4 
    // do more stuff with exitcode 
} 

protected Task<int> runProcess(string id) 
{ 
    var tcs = new TaskCompletionSource<int>(); 

    var process = new Process 
    { 
     StartInfo = { FileName = @"C:\a_very_slow_task.bat" }, 
      EnableRaisingEvents = true 
     }; 
     process.Exited += (sender, args) => tcs.SetResult(((Process)sender).ExitCode);    

     process.Start(); 

     return tcs.Task; 
    } 
} 

आदर्श रूप में, किसी पोस्ट क्रिया के साथ एक एपीआई बाकी कॉल (/ कार्य/slowtask/लांच) करते हैं और उम्मीद करते हैं एक 202 (स्वीकृत) बहुत तेजी से होगा।

फिडलर वेब डीबगर का उपयोग करके मैं अनुरोध करता हूं, कोड लॉन्च (// 1) में प्रवेश करता है, फिर प्रतीक्षा (// 3) पर जाता है, धीमा कार्य बनाया जाता है और शुरू किया जाता है और स्वीकृत लौटाया जाता है (// 2)। लेकिन इस बिंदु पर, फिडलर 202 परिणाम नहीं दिखाता है। संलग्न छवि देखें:

http://imageshack.us/photo/my-images/703/fiddler1.png/

जब धीमी गति से कार्य समाप्त हो जाती है, कोड exitcode (// 4) और उसके बाद 202 Fiddler में कब्जा कर लिया है पर कब्जा जारी है।

यह बहुत अजीब है, क्योंकि मैंने बहुत समय पहले वापसी की थी। मुझे क्या याद आ रहा है 202 बहुत तेज़ लौटने और कार्य के बारे में भूलने के लिए मैं उस कोड को कैसे बदल सकता हूं।

नोट: मुझे पता है कि गैर ढांचे 4.5 सुविधाओं के साथ यह कैसे करना है, मैं सीखने की कोशिश कर रहा हूं कि एसिंक/प्रतीक्षा का उपयोग कैसे करें।

+1

मुझे लगता है कि ऐसा इसलिए है क्योंकि 'runProcessAsync() 'अनुरोध के सिंक्रनाइज़ेशन संदर्भ पर चलता है। यदि आप यह नहीं चाहते हैं, तो आप 'टास्क.रुन (() => runProcessAsync (id)) का उपयोग कर सकते हैं; '। लेकिन इसके साथ सावधान रहें, क्योंकि आईआईएस उस समय के दौरान आपके एपडोमेन को रीसायकल कर सकता है, इसलिए एक मौका है 'runProcessAsync()' पूरा नहीं होगा। – svick

+0

मैंने ऐसा किया और काम करता है। यह एक शर्म की बात है कि आपने उचित उत्तर नहीं दिया है, क्योंकि आपने मेरी समस्या हल की है – Jordi

उत्तर

4

मुझे लगता है कि ऐसा इसलिए है क्योंकि runProcessAsync() अनुरोध के सिंक्रनाइज़ेशन संदर्भ पर चलता है। यदि आप यह नहीं चाहते हैं, तो आप Task.Run(() => runProcessAsync(id)); का उपयोग कर सकते हैं। लेकिन इसके साथ सावधान रहें, क्योंकि आईआईएस उस समय के दौरान आपके ऐपडोमेन को रीसायकल कर सकता है, इसलिए runProcessAsync() पूरा होने का मौका नहीं है।

1

को Task वापस करने के लिए बस सबसे आसान तरीका है। याद रखें, async विधियों को Task/Task<T> जब भी संभव हो, और केवल void लौटाएं जब में है।

हालांकि, मुझे आपको सावधान रहना चाहिए कि यह काफी खतरनाक है। एएसपी.नेट एक HTTP सर्वर है, इसलिए यदि कोई सक्रिय अनुरोध नहीं है, तो यह आपके ऐपडोमेन को नीचे ले जाने के लिए स्वतंत्र महसूस करेगा। इसका मतलब यह होगा कि "एक्जिकोड के साथ और अधिक सामान करें" बस पृथ्वी के चेहरे को छोड़ देगा।

मेरे पास blog post with a BackgroundTaskManager है जिसका उपयोग आप Task एस को एएसपी.NET रनटाइम के साथ पंजीकृत करने के लिए उपयोग कर सकते हैं। यदि पंजीकृत Task एस पंजीकृत नहीं हैं तो यह ऐपडोमेन शटडाउन में देरी करने का प्रयास करेगा। हालांकि, यह सिर्फ एक "सर्वश्रेष्ठ प्रयास" है; उस तरह की चीज़ के लिए कोई गारंटी नहीं है। एएसपी.NET में चल रहे किसी भी कोड जो एक सक्रिय अनुरोध से जुड़ा नहीं है एक खतरनाक स्थिति है।

+0

मुझे समझ में नहीं आ रहा है, 'कार्य' सहायता के वापसी प्रकार को क्यों बदलना होगा? यदि समस्या सिंक्रनाइज़ेशन संदर्भ के साथ है, तो वह कुछ भी नहीं बदलेगा, नहीं? – svick

संबंधित मुद्दे