![]() |
Web Development »
ASP.NET »
Howto
Intermediate
License: The Code Project Open License (CPOL)
Problem with Response.Write - Changing Dynamic Contents without CorruptionBy Mohammad HefnyChanging 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
|
||||||||
|
Advanced Search |
|
|
|
||||||||||||||||
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");
}
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: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:
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.
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.
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);
}
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.
| You must Sign In to use this message board. | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
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 |