2009-08-08 5 views
8

मेरे पास एक एएसपी.नेट एमवीसी एप्लीकेशन है जो वर्तमान में वेब क्लाइंट क्लास का उपयोग करता है ताकि बाहरी वेब सेवा को नियंत्रक कार्रवाई के भीतर से सरल कॉल किया जा सके।एएसपी.नेट एमवीसी के भीतर असीमित रूप से वेब क्लाइंट का उपयोग करना?

वर्तमान में मैं डाउनलोडस्ट्रिंग विधि का उपयोग कर रहा हूं, जो तुल्यकालिक रूप से चलता है। मैंने उन मुद्दों पर भाग लिया है जहां बाहरी वेब सेवा अनुत्तरदायी है, जिसके परिणामस्वरूप मेरा पूरा एएसपी.नेट आवेदन थ्रेड-भूखे और उत्तरदायी नहीं है।

इस समस्या को ठीक करने का सबसे अच्छा तरीका क्या है? एक DownloadStringAsync विधि है, लेकिन मुझे यह सुनिश्चित नहीं है कि इसे नियंत्रक से कैसे कॉल करें। क्या मुझे AsyncController क्लास का उपयोग करने की आवश्यकता है? यदि हां, तो AsyncController और DownloadStringAsync विधि कैसे इंटरैक्ट करता है?

सहायता के लिए धन्यवाद।

उत्तर

7

मुझे लगता है कि AsyncControllers का उपयोग करने से आपको यहां मदद मिलेगी क्योंकि वे अनुरोध थ्रेड से प्रसंस्करण को ऑफ़लोड करते हैं।

मैं कुछ इस तरह का उपयोग करें (this article में वर्णित के रूप घटना पद्धति का उपयोग कर) चाहते हैं:

public class MyAsyncController : AsyncController 
{ 
    // The async framework will call this first when it matches the route 
    public void MyAction() 
    { 
     // Set a default value for our result param 
     // (will be passed to the MyActionCompleted method below) 
     AsyncManager.Parameters["webClientResult"] = "error"; 
     // Indicate that we're performing an operation we want to offload 
     AsyncManager.OutstandingOperations.Increment(); 

     var client = new WebClient(); 
     client.DownloadStringCompleted += (s, e) => 
     { 
      if (!e.Cancelled && e.Error == null) 
      { 
       // We were successful, set the result 
       AsyncManager.Parameters["webClientResult"] = e.Result; 
      } 
      // Indicate that we've completed the offloaded operation 
      AsyncManager.OutstandingOperations.Decrement(); 
     }; 
     // Actually start the download 
     client.DownloadStringAsync(new Uri("http://www.apple.com")); 
    } 

    // This will be called when the outstanding operation(s) have completed 
    public ActionResult MyActionCompleted(string webClientResult) 
    { 
     ViewData["result"] = webClientResult; 
     return View(); 
    } 
} 

और सुनिश्चित करें कि आप (Global.asax.cs में) सेटअप जो कुछ रास्तों को आप की जरूरत है, उदाहरण के लिए:

public class MvcApplication : System.Web.HttpApplication 
{ 
    public static void RegisterRoutes(RouteCollection routes) 
    { 
     routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

     routes.MapAsyncRoute(
      "Default", 
      "{controller}/{action}/{id}", 
      new { controller = "Home", action = "Index", id = "" } 
     ); 
    } 
} 
+0

क्या वेब क्लाइंट एसिंक कॉल में टाइमआउट जोड़ने का कोई तरीका है? –

+1

बस एक नोट, ऐसा लगता है कि यह जवाब 0 9 में एमवीसी 1.0 दिनों में पोस्ट किया गया था। अब एमवीसी 2/3 के साथ जवाब थोड़ा अलग है। MapAsyncRoute विधि चली गई है और अब इसकी आवश्यकता नहीं है। साथ ही, MyAction विधि को अब MyActionAsync में बदलना होगा।अन्यथा, सब कुछ एक ही तरीके से काम करता है। – BFree

3

डाउनलोडस्ट्रिंगएसिंक विधि एक ईवेंट मॉडल का उपयोग करती है, जब यह समाप्त हो जाती है तो DownloadStringCompleted उठाती है। यदि आप WebClient.CancelAsync() पर कॉल करके बहुत अधिक समय ले रहे हैं तो आप अनुरोध को भी रोक सकते हैं। यह आपके मुख्य अनुरोध थ्रेड और आपके वेब क्लाइंट थ्रेड को समानांतर में चलाने के लिए देगा, और आपको यह तय करने की अनुमति देगा कि आप अपने मुख्य थ्रेड को लौटने से पहले कितनी देर प्रतीक्षा करना चाहते हैं।

नीचे दिए गए उदाहरण में, हम डाउनलोड शुरू करते हैं और ईवेंट हैंडलर सेट करते हैं जिसे हम समाप्त होने पर लागू करना चाहते हैं। DownloadStringAsync तुरंत लौटता है, इसलिए हम अपने शेष अनुरोध को संसाधित करना जारी रख सकते हैं।

इस ऑपरेशन पर अधिक बारीक नियंत्रण प्रदर्शित करने के लिए, जब हम अपने नियंत्रक कार्रवाई के अंत तक पहुंच जाते हैं, तो हम यह देखने के लिए जांच सकते हैं कि डाउनलोड अभी तक पूरा हो गया है या नहीं; यदि नहीं, तो इसे 3 और सेकंड दें और फिर निरस्त करें।

string downloadString = null; 

ActionResult MyAction() 
{ 
    //get the download location 
    WebClient client = StartDownload(uri); 
    //do other stuff 
    CheckAndFinalizeDownload(client); 
    client.Dispose(); 
} 

WebClient StartDownload(Uri uri) 
{ 
    WebClient client = new WebClient(); 
    client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(Download_Completed); 
    client.DownloadStringAsync(uri); 
    return client; 
} 

void CheckAndFinalizeDownload(WebClient client) 
{ 
    if(this.downloadString == null) 
    { 
     Thread.Sleep(3000); 
    } 
    if(this.downloadString == null) 
    { 
     client.CancelAsync(); 
     this.downloadString = string.Empty; 
    } 
} 

void Download_Completed(object sender, DownloadStringCompletedEventArgs e) 
{ 
    if(!e.Cancelled && e.Error == null) 
    { 
     this.downloadString = (string)e.Result; 
    } 
} 
+0

मेरा मानना ​​है कि यह दृष्टिकोण अभी भी अनुरोध धागा को अवरुद्ध करेगा हालांकि - आप अभी भी अपने स्लीप कॉल के दौरान अनुरोध थ्रेड पर हैं। Async नियंत्रक यहां सहायता करेंगे क्योंकि जब आप बाह्य संसाधन की प्रतीक्षा कर रहे हों तो वे अनुरोध थ्रेड को मुक्त कर देंगे। –

+0

@ माइकल वास्तव में। यह दृष्टिकोण अनुरोध थ्रेड के साथ समानांतर में चलाएगा जब तक कि वेब क्लाइंट अनुरोध तब तक समाप्त नहीं होता जब तक कि नियंत्रक थ्रेड ने अन्य सभी चीजों को करने की आवश्यकता न हो - जिस बिंदु पर नियंत्रक चुनता है कि ब्लॉक/नींद या जारी रखना है या नहीं। मुझे यह धारणा नहीं मिली कि सवाल विशेष रूप से AsyncController का उपयोग करने के तरीके के आसपास है, बल्कि वेब क्लाइंट को असीमित रूप से कैसे काम करना है। यह सवाल का गलत पठन हो सकता है। –

+0

@Rex हाँ, मुझे लगता है कि वेब ऐप के विवरण से "थ्रेड-भूखे और उत्तरदायी" होने की संभावना है कि यह संभवतः ओपी अनुरोध थ्रेड से बाहर हो रहा है। 3 सेकंड तक बाहरी प्रतिक्रिया को सीमित करने से थोड़ा सा मदद मिलेगी (यदि आपके बाहरी अनुरोध पहले से अधिक समय ले रहे थे), लेकिन यह अभी भी धागा को पकड़ने के लिए काफी लंबा समय है और इसलिए यह स्केल नहीं करेगा। –

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