2011-01-04 4 views
15

मेरे पास कुछ उपयोगिता क्रियाएं हैं जो return Content("my text","text/plain") के माध्यम से टेक्स्ट आउटपुट लौटाती हैं।लंबे समय से चलने वाली कार्रवाई के लिए स्ट्रीमिंग टेक्स्ट आउटपुट?

कभी-कभी इन विधियों को चलाने के लिए कुछ मिनट लगते हैं (यानी लॉग पार्सिंग, डेटाबेस रखरखाव)।

मैं अपनी क्रिया विधि को संशोधित करना चाहता हूं ताकि सभी आउटपुट को एक बार में लौटने की बजाय, टेक्स्ट तैयार होने पर क्लाइंट को स्ट्रीम किया जा सके।

यहाँ एक काल्पनिक उदाहरण है:

public ActionResult SlowText() 
{ 
    var sb = new System.Text.StringBuilder(); 
    sb.AppendLine("This happens quickly..."); 
    sb.AppendLine("Starting a slow 10 second process..."); 
    System.Threading.Thread.Sleep(10000); 
    sb.AppendLine("All done with 10 second process!"); 
    return Content(sb.ToString(), "text/plain"); 
} 

लिखा है, इस कार्रवाई 10 सेकंड के बाद पाठ की तीन लाइनों वापस आ जाएगी। मैं चाहता हूं कि प्रतिक्रिया स्ट्रीम को खोलने का एक तरीका है, और पहले दो पंक्तियों को तुरंत वापस कर दें, और फिर 10 सेकंड के बाद तीसरी पंक्ति।

मुझे यह 10+ साल पहले प्रतिक्रिया ऑब्जेक्ट का उपयोग कर क्लासिक एएसपी 3.0 में करना याद है। क्या यह पूरा करने के लिए कोई आधिकारिक, एमवीसी-अनुकूल तरीका है?

-

अद्यतन: अनुप्रयोग में उस्तरा .cshtml उपयोग करते हुए; लेकिन इन कार्यों के लिए किसी भी विचार (केवल ContentResult) का उपयोग नहीं कर रहा है।

+1

रेज़र या एएसपीएक्स? अंतर यह है कि रेजर इंजन आउटपुट स्ट्रीमिंग की अनुमति नहीं देता है। – Buildstarted

+0

हम एक ही समस्या में भागते हैं और हम सीधे नियंत्रक में Response.OutputStream का भी उपयोग करते हैं। मुझे यह जानकर उत्सुकता है कि क्या आपको कोई समाधान मिल रहा है? –

उत्तर

5

सीधे Response ऑब्जेक्ट पर लिखना चाहिए, लेकिन केवल कुछ साधारण मामलों में। कई एमवीसी विशेषताएं आउटपुट लेखक प्रतिस्थापन (जैसे आंशिक विचार, रेजर व्यू इंजन, और अन्य) पर निर्भर करती हैं और यदि आप सीधे प्रतिक्रिया पर लिखते हैं तो आपका परिणाम आदेश से बाहर हो जाएगा।

हालांकि, यदि आप दृश्य का उपयोग नहीं करते हैं और इसके बजाय सीधे नियंत्रक में लिखते हैं तो आपको ठीक होना चाहिए (मान लें कि आपकी कार्रवाई को बाल क्रिया के रूप में नहीं कहा जा रहा है)।

+0

गॉथस के लिए धन्यवाद। मैं सीधे "नियंत्रक" को नियंत्रक के अंदर 'प्रतिक्रिया' में जोड़ता हूं ... आपकी राय में, क्या मुझे 'स्ट्रीमिंग कंटेंट रीसेट' एक्शन रिसेट लिखना चाहिए और उसे वापस करना चाहिए? या कुछ विशेष परिस्थितियों में नियंत्रक के अंदर प्रतिक्रिया वस्तु के साथ गड़बड़ करना ठीक है। इस पर किसी और के "कोड गंध" की भावना से प्यार होगा। धन्यवाद। – Portman

+1

हां, अगर मैं ऐसा करना चाहता हूं तो शायद मैं एक नया 'स्ट्रीमिंगकंटेंट रिसेट' लिखूंगा जो शायद कन्स्ट्रक्टर के माध्यम से 'फनक' स्वीकार कर लेगा जो काम करने के लिए आवश्यक काम का प्रतिनिधित्व करेगा। – marcind

1

मैं पूरी तरह से एमवीसी नियंत्रक को छोड़ दूंगा क्योंकि आप किसी भी तरह से encapsulation तोड़ने जा रहे हैं। इसके स्थान पर मैं उपरोक्त आउटपुट स्ट्रीम पर सीधे स्ट्रीमिंग, एक बैरेनकेड IHttpHandler कार्यान्वयन का उपयोग करता हूं।

1

यदि आप मूल रूप से इरादे से अधिक समय लेते हैं तो आप ब्राउज़र टाइमआउट पर खुद को उजागर कर रहे हैं। तब आपके पास क्या हुआ/पुनर्प्राप्त करने का कोई तरीका नहीं है जब तक कि आप एक अलग विधि को लागू न करें जो लंबी चल रही प्रक्रिया पर जानकारी देता है।

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

एक लंबे चल प्रक्रिया शुरू करने के लिए, आप कुछ इस तरह कर सकते हैं:

// in the controller class 
delegate void MyLongProcess(); 
//... 
// in the method that starts the action 
MyLongProcess processTask = new MyLongProcess(_someInstance.TheLongRunningImplementation); 
processTask.BeginInvoke(new AsyncCallback(EndMyLongProcess), processTask); 
//... 
public void EndMyLongProcess(IAsyncResult result) 
{ 
    try{ 
     MyLongProcess processTask = (MyLongProcess)result.AsyncState; 
     processTask.EndInvoke(result); 
     // anything you needed at the end of the process 
    } catch(Exception ex) { 
     // an error happened, make sure to log this 
     // as it won't hit the global.asax error handler      
    } 
} 

के लिए जहां कार्रवाई है कि हुआ लॉग रखूँ रूप में, यह तुम कितनी देर तक रहते थे चाहते हैं कि आप पर निर्भर है यह होना था। यह एक स्थिर क्षेत्र/वर्ग के रूप में सरल हो सकता है जहां आप चल रही प्रक्रिया की जानकारी जोड़ते हैं, या इसे डेटा स्टोर में सहेजते हैं जहां यह एप्लिकेशन रीसायकल से बच सकता है।

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

0

Response.Flush और BufferOutput से false पर आज़माएं। ध्यान दें कि यह विभिन्न क्रिया परिणामों के साथ काम करेगा, आपको सीधे response ऑब्जेक्ट में लिखना होगा। शायद आप इसे AsyncController के साथ संयोजन के साथ उपयोग कर सकते हैं।

1

आप ContentStreamingResult जैसे अपने कस्टम एक्शन रिसैट को कार्यान्वित कर सकते हैं और ExecuteResult विधि में HttpContext, HttpRequest और HttpResponse का उपयोग कर सकते हैं।

public class ContentStreamingResult : ActionResult 
    { 
     private readonly TextReader _reader; 

     public ContentStreamingResult(TextReader reader) 
     { 
      _reader = reader; 
     } 

     public override void ExecuteResult(ControllerContext context) 
     { 
      var httpContext = context.HttpContext; 
      //Read text from the reader and write to the response 
     } 
    } 

public class YourController : Controller 
    { 
     public ContentStreamingResult DownloadText() 
     { 
      string text = "text text text"; 
      return new ContentStreamingResult(new System.IO.StringReader(text)); 
     } 
    }