Writing A Page To A String

0 comments suggest edit

ASP.NET Pages are designed to stream their output directly to a response stream. This can be a huge performance benefit for large pages as it doesn’t require buffering and allocating very large strings before rendering. Allocating large strings can put them on the Large Object Heap which means they’ll be sticking around for a while.

string However, there are many cases in which you really want to render a page to a string so you can perform some post processing. I wrote about one means using a Response filter eons ago.

However, recently, I learned about a method of the Page class I never noticed which allows me to use a much lighter weight approach to this problem.

The method in question is CreateHtmlTextWriter which is protected, but also virtual.

So here’s an example of the code-behind for a page that can leverage this method to filter the output before its sent to the browser.

public partial class FilterDemo : System.Web.UI.Page
{
  HtmlTextWriter _oldWriter = null;
  StringWriter _stringWriter = new StringWriter();

  protected override HtmlTextWriter CreateHtmlTextWriter(TextWriter tw)
  {
    _oldWriter = base.CreateHtmlTextWriter(tw);
    return base.CreateHtmlTextWriter(_stringWriter);
  }

  protected override void Render(HtmlTextWriter writer)
  {
    base.Render(writer);
    string html = _stringWriter.ToString();
    html = html.Replace("REPLACE ME!", "IT WAS REPLACED!");
    _oldWriter.Write(html);
  }
}

In the CreateHtmlTextWriter method, we simply use the original logic to create the HtmlTextWriter and store it away in an instance variable.

Then we use the same logic to create a new HtmlTextWriter, but this one has our own StringWriter as the underlying TextWriter. The HtmlTextWriter passed into the Render method is the one we created. We call Render on that and grab the output from the StringWriter and now can do all the replacements we want. We finally write the final output to the original HtmlTextWriter which is hooked up to the response.

A lot of caveats apply in using this technique. First, as I mentioned before, for large pages, you could be killing scalability and performance by doing this. Also, I haven’t tested this with output caching, async pages, etc… etc…, so your mileage may vary.

Note, if you want to call one page from another, and get the output as a string within the first page, you can pass your own TextWriter to Server.Execute, so this technique is not necessary in that case.

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

14 responses

  1. Avatar for Gene
    Gene May 28th, 2009

    With regard to asp.net streaming a page, Steve Souders (YSlow) mentions using www.stevesouders.com/.../flushing-the-document-...
    (stackoverflow suggests Response.Flush() stackoverflow.com/.../can-i-flush-the-buffer-ea... )
    to start the browser downloading other files rather than waiting for the html doc to finish downloading.
    How/Does this work with MVC?

  2. Avatar for Morten Lyhr
    Morten Lyhr May 29th, 2009

    How can I do this in MVC?
    I would really like to use MVC as a template engine to create email, xml content to be stored on the servers disk etc.

  3. Avatar for Victor Kornov
    Victor Kornov May 29th, 2009

    Doesn't need any CreateHtmlTextWriter:
    protected override void Render(HtmlTextWriter writer)
    {
    var sw = new StringWriter();
    var w = new HtmlTextWriter(sw);
    base.Render(w);
    string html = sw.ToString();
    html = html.Replace("REPLACE ME!", "IT WAS REPLACED!");
    writer.Write(html);
    }

  4. Avatar for Andrew Peters
    Andrew Peters May 29th, 2009
  5. Avatar for neonp
    neonp May 29th, 2009

    Hello,
    Maybe did I missed something, but why not using an HttpModule to solve this problem ? you could filter the response easily. You won't have this problem of string huge size. Correct me if I'm wrong.

  6. Avatar for Haacked
    Haacked May 29th, 2009

    @neonp the point of this is that it hints at a means of rendering an ASP.NET MVC view to a string, a common request.

  7. Avatar for guoyz
    guoyz May 29th, 2009

    what's meaning?
    can you translate it to chinese?

  8. Avatar for Chris Charabaruk
    Chris Charabaruk May 29th, 2009

    Off the tope of your head, do you know if it'd be possible to use this to generate page output that'll never be sent to a user's browser (say, so you can use views to build e-mails to send to users instead)?

  9. Avatar for Haacked
    Haacked May 29th, 2009

    @Chris yes, exactly. You don't have to send the output to the response using this approach if you don't want to.

  10. Avatar for Paul St. Amant, softomic.com
    Paul St. Amant, softomic.com May 29th, 2009

    Interesting idea. Maybe you could even store a whole website in a single blob and just parse it with a single function. A whole book can be a single pdf file, why not a whole site? Maybe not practical, but an interesting concept.

  11. Avatar for Jon
    Jon May 30th, 2009

    I recently required the need to return the output from a Partial view to put in a JSON object. I found this and just wondered if this was a better approach?

  12. Avatar for jinrutan
    jinrutan June 3rd, 2009

    That's great idea,so helpful!
    I still using response filter,but i think using the solution will be great!

  13. Avatar for casino en france
    casino en france March 22nd, 2011

    Ok why was my comment deleted I thoought we were friends ! ;(


    [editor: Any comment with a URL to an online casino appears to be SPAM to me! Are you legitimately commenting? Or just a drive-by spammer? :)]

  14. Avatar for Firas Nizam
    Firas Nizam September 19th, 2017

    Perfect Example, thanks for sharing