2011-08-17 9 views
7

मुझे HTML आउटपुट कैप्चर करने, इसे स्ट्रिंग में बदलने के लिए एक क्रिया पर निम्न फ़िल्टर मिला है, स्ट्रिंग को संशोधित करने के लिए कुछ ऑपरेशन करें, और नई सामग्री के साथ ContentResult को वापस करें स्ट्रिंग। दुर्भाग्य से, मैं एक खाली स्ट्रिंग के साथ समाप्त रहता है।नियंत्रक एक्शन फ़िल्टर के साथ एचटीएमएल आउटपुट कैप्चर करना

private class UpdateFilter : ActionFilterAttribute 
    { 
     private Stream stream; 

     public override void OnActionExecuting(ActionExecutingContext filterContext) 
     { 
      stream = filterContext.HttpContext.Response.Filter; 
      stream = new MemoryStream(); 
      filterContext.HttpContext.Response.Filter = stream; 
     } 

     public override void OnResultExecuted(ResultExecutedContext filterContext) 
     { 
      StreamReader responsereader = new StreamReader(filterContext.HttpContext.Response.Filter); //empty stream? why? 
      responsereader.BaseStream.Position = 0; 
      string response = responsereader.ReadToEnd(); 
      ContentResult contres = new ContentResult(); 
      contres.Content = response; 
      filterContext.Result = contres; 
     } 
    } 

मैं नीचे पिन कर दिया है कि StreamReader (धारा) .ReadToEnd() एक खाली स्ट्रिंग देता है, लेकिन मैं बाहर क्यों समझ नहीं सकता।

कोई विचार यह कैसे ठीक करें?

संपादित करें: मैंने ऑनएक्शन एक्स्क्लेटेड टू ऑनरसल्ट एक्स्क्टेडड को बदल दिया है, और अब व्यू उत्पन्न होने के बाद इसे कॉल किया गया है, लेकिन स्ट्रीम अभी भी खाली है!

उत्तर

11

मैं द्वारा इस हल HttpWriter को अपहरण कर रहा है, और इसे प्रतिक्रिया के बजाय StringBuilder में लिखना है, और उसके बाद आउटपुट में लिखने से पहले प्रतिक्रिया के साथ जो कुछ भी करने की आवश्यकता है उसे कर रहा है।

private class UpdateFilter : ActionFilterAttribute 
    { 
     private HtmlTextWriter tw; 
     private StringWriter sw; 
     private StringBuilder sb; 
     private HttpWriter output; 

     public override void OnActionExecuting(ActionExecutingContext filterContext) 
     { 
      sb = new StringBuilder(); 
      sw = new StringWriter(sb); 
      tw = new HtmlTextWriter(sw); 
      output = (HttpWriter)filterContext.RequestContext.HttpContext.Response.Output; 
      filterContext.RequestContext.HttpContext.Response.Output = tw; 
     } 

     public override void OnResultExecuted(ResultExecutedContext filterContext) 
     { 
      string response = sb.ToString(); 
      //response processing 
      output.Write(response); 
     } 
    } 
+12

एक चेतावनी है: एक्शन फ़िल्टर में इंस्टेंस चर का उपयोग करने की अनुशंसा नहीं की जाती है। आपको प्रत्येक अनुरोध पर ActionFilterAttribute का एक नया उदाहरण प्राप्त करने की गारंटी नहीं है। मैंने इस जवाब से मेरा कोड आधारित किया और प्रति सेकंड हजारों अनुरोधों के साथ उत्पादन में जाने पर परेशानी हो गई - तार (धागे) पार हो रहे थे। filterContext.HttpContext.Items में इंस्टेंस चर को संग्रहीत करें जैसा कि इस पोस्ट में सुझाया गया है: http: // stackoverflow।कॉम/ए/8937793/14044 9 – jaminto

2

इसे पढ़ने से पहले Position = 0; सेट करके स्ट्रीम को शुरुआत में रीवाइंड करने का प्रयास करें।

public override void OnActionExecuted(ActionExecutedContext filterContext) 
{ 
    stream.Position = 0; 
    string response = new StreamReader(stream).ReadToEnd(); 
    ContentResult contres = new ContentResult(); 
    contres.Content = response; 
    filterContext.Result = contres; 
} 
+0

कि यह ठीक नहीं हुआ है, लेकिन यह मेरे लिए नेतृत्व किया नोटिस कि स्थिति पहले से ही 0 है। तो ऐसा लगता है कि स्ट्रीम खाली होनी चाहिए .... मुझे आश्चर्य है कि क्यों – yoozer8

0

क्या आप सत्यापित कर सकते हैं कि स्ट्रीम ऑनएक्शन एक्सेक्टेड-विधि में पूर्ण नहीं है? मुझे यकीन है कि धारा-चर के राज्य प्रक्रिया के माध्यम से संग्रहित किया जा रहा है नहीं कर रहा हूँ ..

तुम क्यों filterContext से बाहर धारा प्राप्त करने की कोशिश नहीं है:

public override void OnActionExecuted(ActionExecutedContext filterContext) 
{ 
    var stream = filterContext.HttpContext.Response.Filter; 
    string response = new StreamReader(stream).ReadToEnd(); 
    ContentResult contres = new ContentResult(); 
    contres.Content = response; 
    filterContext.Result = contres; 
} 
+0

अच्छा, मैंने सोचा कि यह जवाब होगा, लेकिन मुझे एक ही समस्या है। स्ट्रीम को मैं FontContext.HttpContext.Response.Filter से प्राप्त करता हूं। – yoozer8

1

मुझे लगता है कि मैंने ऐसा करने के लिए एक बहुत अच्छा तरीका विकसित किया है।

  • एक कस्टम
  • इस फिल्टर एक सार विधि है जो एक धारा
  • यह प्रतिनिधि है, और इसलिए सार विधि लेता धारा के पास पर कहा जाता है के लिए एक प्रतिनिधि लेता है के साथ प्रतिक्रिया फ़िल्टर बदलें , यानी जब सभी एचटीएमएल उपलब्ध हैं
  • OnClose विधि को ओवरराइड करें और स्ट्रीम के साथ खेलें।

public abstract class ReadOnlyActionFilterAttribute : ActionFilterAttribute 
{ 
    private delegate void ReadOnlyOnClose(Stream stream); 

    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     filterContext.HttpContext.Response.Filter = new OnCloseFilter(
      filterContext.HttpContext.Response.Filter, 
      this.OnClose); 
     base.OnActionExecuting(filterContext); 
    } 

    protected abstract void OnClose(Stream stream); 

    private class OnCloseFilter : MemoryStream 
    { 
     private readonly Stream stream; 

     private readonly ReadOnlyOnClose onClose; 

     public OnCloseFilter(Stream stream, ReadOnlyOnClose onClose) 
     { 
      this.stream = stream; 
      this.onClose = onClose; 
     } 

     public override void Close() 
     { 
      this.Position = 0; 
      this.onClose(this); 
      this.Position = 0; 
      this.CopyTo(this.stream); 
      base.Close(); 
     } 
    } 
} 

फिर आप स्ट्रीम तक पहुंच और एचटीएमएल प्राप्त करने के लिए एक और विशेषता को यह से निकाले जाते हैं कर सकते हैं:

public class MyAttribute : ReadOnlyActionFilterAttribute 
{ 
    protected override void OnClose(Stream stream) 
    { 
     var html = new HtmlDocument(); 
     html.Load(stream); 
     // play with html 
    } 
} 
+0

प्रश्न हालांकि परिणाम अपडेट करने के बारे में है - यह आपके समाधान के साथ संभव नहीं है? – Gaz

+0

@Gaz इसे काम करने के लिए संशोधित करने के लिए पर्याप्त सरल होना चाहिए। काफी समय पहले माफ करना याद नहीं कर सकता! –

+0

@Gaz, यह ओपी को सही दिशा में प्राप्त करना चाहिए। समस्या यह है कि 'filterContext.RequestContext.HttpContext.Response' में डिफ़ॉल्ट स्ट्रीम पढ़ने का समर्थन नहीं करती है, इसलिए आपको स्ट्रीम को प्रतिस्थापित करने की अनुमति है जो पढ़ने की अनुमति देता है। – ps2goat

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