Click here to Skip to main content
6,295,667 members and growing! (10,024 online)
Email Password   helpLost your password?
Web Development » ASP.NET » Howto     Intermediate License: The Code Project Open License (CPOL)

Problem with Response.Write - Changing Dynamic Contents without Corruption

By Mohammad Hefny

Changing HTML content of an ASP.Net page using new technique that handle Response.Write()
C# (C# 1.0, C# 2.0, C# 3.0), VB, .NET, Architect, Dev
Posted:15 May 2008
Views:9,218
Bookmarked:14 times
Unedited contribution
Announcements
Loading...
 
Search    
Advanced Search
printPrint   Broken Article?Report       add Share
  Discuss Discuss   Recommend Article Email
8 votes for this article.
Popularity: 3.97 Rating: 4.40 out of 5

1

2
2 votes, 25.0%
3
1 vote, 12.5%
4
5 votes, 62.5%
5

Introduction

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

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

What is the Problem

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

<table> <tr> <td>
        Hello ( <%Response.Write(@"Mr. XYZ"); %> $MSG$       
</td> </tr> </table>     
All we need to do is to 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 down 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 it, with another on that streams data into a StringBuilder object oPageContents , once the Html is in oPageContents string builder you can read and modify easily. Next step is to write your contents in the actual HtmlTextWriter that is passed as a parameter in the render function. It is pretty straight forward :) .... wait the result is not what why want to do ??!!

The strange thing is that you dont get the desired result instead you get the following result:
BadResult.PNG

I spend couple of days searching why does thing happen. 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 HtmlTextWriter stream sends the data eventually to Response object.
Diagram1.png
So what happens here is that while base.Render() is working, when Response.Write() takeplace it sends data to directly out, while the other data are all stored in our local string builder, then we inject them in to the writer but 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 StringBuilder object as in our previous sample, in the same time, it streams data to writer parameter of type HtmlTextWriter. The data is submitted synchornized to Response object, while another copy is being saved in the string builder 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 now 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 contents without the need to write into HTMLStreamer itself, so it can be used as a separate DLL. For sure if you have any idea 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)

About the Author

Mohammad Hefny


Member

Occupation: Architect
Location: Egypt Egypt

Other popular ASP.NET articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 5 of 5 (Total in Forum: 5) (Refresh)FirstPrevNext
AnswerSimple fix: Use <%= %> instead of <%Response.Write%> PinmemberRick L6:19 9 Oct '08  
GeneralGood work !!! Pinmemberdnpro23:16 21 May '08  
GeneralAlternative PinmemberMatthew Fergusson1:16 20 May '08  
GeneralRe: Alternative PinmemberMohammad Hefny3:26 10 Aug '08  
GeneralRe: Alternative PinmemberJ. Moreno9:02 22 Jun '09  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 15 May 2008
Editor: Sean Ewington
Copyright 2008 by Mohammad Hefny
Everything else Copyright © CodeProject, 1999-2009
Web13 | Advertise on the Code Project