Click here to Skip to main content
Click here to Skip to main content
Go to top

Problem with Response.Write - Changing Dynamic Content Without Corruption

, 15 May 2008
Rate this:
Please Sign up or sign in to vote.
Changing HTML content of an ASP.NET page using a new technique that handles Response.Write().

Introduction

When you need to dynamically control the HTML that is generated from your ASP.NET page or control, a popular technique to do that is to override the render function: protected override void Render(HtmlTextWriter writer). It is a function where you can get great power over your control. The function simply sends an HtmlTextWriter, which is a stream where you can write anything and it will appear on the client screen, as we can see in the code below.

protected override void Render(HtmlTextWriter writer)
{
    writer.Write("SayAnthing");
}

The Problem

Now, let us change the page data instead of replacing it. The attached sample contains two ASPX pages, both with the same HTML structure as follows:

<table> <tr> <td>
        Hello ( <%Response.Write(@"Mr. XYZ"); %> $MSG$       
</td> </tr> </table>

All we need to do is replace $MSG$ with a message "How R U?" by capturing the rendering event. The required result should be as in the following figure:

GoodResult.PNG

Let us write the code:

protected override void Render(HtmlTextWriter writer) 
{
    // Create your HTMLTestWriter
   System.Text.StringBuilder oPageContents = new System.Text.StringBuilder();
    System.IO.StringWriter oSW = new System.IO.StringWriter(oPageContents);
    System.Web.UI.HtmlTextWriter oHtmlWriter = new System.Web.UI.HtmlTextWriter(oSW);
    
    // Give the page a fake streamer to capture HTML contents.
    base.Render(oHtmlWriter); 
    oPageContents = oPageContents.Replace("$MSG$", "How R U ?");
    
    // Write data back into the original stream
    System.IO.StringReader oSR = new System.IO.StringReader(oPageContents.ToString ());
    writer.Write(oSR.ReadToEnd ()); 
}

Nothing strange about this code, and it can be found all over the internet. The idea behind it is that you replace the given HtmlTextWriter that you can only write into, with another one that streams data into a StringBuilder object, oPageContents. Once the HTML is in the oPageContents StringBuilder, you can read and modify it easily. The next step is to write your contents in the actual HtmlTextWriter that is passed as a parameter in the Render function. It is pretty straightforward Smile | :) Wait, the result is not what you want??!!

The strange thing is that you don't get the desired result; instead, you get the following result:

BadResult.PNG

I spent a couple of days searching why this happened. And finally, I found the answer. Response.Write() does not send its contents through base.Render that is used to render the control. Response.Write(), in fact, the HtmlTextWriter stream sends the data eventually to the Response object.

Diagram1.png

So what happens here is that while base.Render() is working, when Response.Write() takes place, it sends data directly out, while the other data are all stored in our local StringBuilder, and then we inject them in to the writer, but then it is too late, as the order of streaming output now has been corrupted.

Solution - HTML Streamer

HTMLStreamer solves this issue by acting as a double streamer. It streams data to a StringBuilder object as in our previous sample. At the same time, it streams data to a writer parameter of type HtmlTextWriter. The data is submitted synchronized to the Response object, while another copy is saved in the StringBuilder object.

public class HTMLStreamer: System.IO.StringWriter 
{ 
    protected System.Web.UI.HtmlTextWriter mHtmlTextWriter;
    public HTMLStreamer(System.Text.StringBuilder oStringBuilder, 
                        System.Web.UI.HtmlTextWriter innerWriter) 
        : base(oStringBuilder)
     { 
        mHtmlTextWriter = innerWriter;
     }
    
    public override void Write(string value) 
    { 
        // Change content dynamically here.
        if (value.IndexOf("$MSG$")!=-1) 
        {
            value = value.Replace("$MSG$","How R U ?"); 
        }
        mHtmlTextWriter.Write(value); base.Write(value); 
    }
    
    public override void Write(char[] buffer, int index, int count)
    { 
        mHtmlTextWriter.Write(buffer, index, count);
        base.Write(buffer, index, count);
    } 

    public override void Write(char value) 
    { 
        mHtmlTextWriter.Write(value);
        base.Write(value);
    } 
}

Now back to the Render() function; it should be handled as follows:

protected override void Render(HtmlTextWriter writer) 
{ 
    // Create your string builder.
    System.Text.StringBuilder oPageContents = new System.Text.StringBuilder();
   
    // Create HTMLStreamer and put both writer & oPageContents into it.
    HTMLStreamer oSW = new HTMLStreamer(oPageContents, writer); 
   
    // Create HTMLTextWriter that contains the double-stream class "HTMLStreamer"
    System.Web.UI.HtmlTextWriter oHtmlWriter = new System.Web.UI.HtmlTextWriter(oSW);
   
    // Get HTML contents.
    base.Render(oHtmlWriter); 
}

Enhancements

A delegate is called in all Write() functions of HTMLStreamer so that it can be used by the page to change the contents without the need to write into the HTMLStreamer itself and so it can be used as a separate DLL. If you have any idea on how to capture Response.Write(), please let me know.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Mohammad Said Hefny
Architect
Egypt Egypt
No Biography provided
Follow on   Twitter

Comments and Discussions

 
Suggestion" If you have any idea on how to capture Response.Write() ... " PinmemberMicke2nd14-Mar-12 4:42 
GeneralExcellent work! Pinmemberfeguardia27-Oct-09 9:59 
AnswerSimple fix: Use &lt;%= %&gt; instead of &lt;%Response.Write%&gt; PinmemberRick L9-Oct-08 5:19 
GeneralGood work !!! Pinmemberdnpro21-May-08 22:16 
GeneralAlternative PinmemberMatthew Fergusson20-May-08 0:16 
GeneralRe: Alternative PinmemberMohammad Hefny10-Aug-08 2:26 
GeneralRe: Alternative PinmemberJ. Moreno22-Jun-09 8:02 
AnswerRe: Alternative PinmemberMicke2nd14-Mar-12 4:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140916.1 | Last Updated 15 May 2008
Article Copyright 2008 by Mohammad Said Hefny
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid