Reputation: 398
I have a requirement of being able to have dynamic customer-specific text substitutions on every Page. For instance, I can put "{CarMake}" anywhere in a Page, and it will change "{CarMake}" to "Ford" for our Ford customer, "Toyota" for Toyota, etc. We're doing this with a custom Page.Render function, which will do the replacements on the rendered html just before being output to the client.
A custom Page.Render is essentially the same idea as a Response Filter, and I have already read Eilon Lipton's fantastic explanation of this error, but I am still left confused by why this is a problem in my particular case.
The .ASPX page markup contains, within an UpdatePanel:
<p>{CarMake}</p>
Then the rendered HTML of the loaded page contains:
<p>Ford</p>
Then, when the UpdatePanel does a Partial PostBack, I am getting the aforementioned parsing error of the UpdatePanel's response, which appears to contain the correctly substituted text (just like the initial render of the HTML):
"1|#||4|2325|updatePanel|UpdatePanelCars|...<p>Ford</p>..."
So, if the rendered HTML is exactly the same, why is this causing a problem? How is the clientside parsing even detecting a difference?
For reference, the code doing the substitution is this:
class TemplatedPage: System.Web.UI.Page
{
...
protected override void Render(HtmlTextWriter writer)
{
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
HtmlTextWriter hWriter = new HtmlTextWriter(sw);
base.Render(hWriter); //obtain full html markup, still containing {} at this point
sb.Replace("{CarMake}", "Ford");
//other Replacements...
string alteredPageContents = sb.ToString();
writer.Write(alteredPageContents);
}
}
I have tried setting EnableEventValidation to false, but that has no effect.
Upvotes: 0
Views: 180
Reputation: 9470
I guess your replacement templates {something}
are inside server side controls like <asp:Literal runat="server">{something}</asp:Literal>
. A aspx page in its lifecycle passes through many stages and render
is very close to the end. Before running render
the page saves ViewState
which keeps the state (content) of all controls and any changes in server control content result in mismatch of post
ed request and saved ViewState
.
The latest moment you can modify the page content is page_PreRenderComplete
event handler.
Of course, if the page is not post
ed back (in full or partially) then it doesn't matter.
In fact I use very similar code in many (all) pages but I only reorder control rendering (put script
to the bottom and so on). Replacements inside render
resulted in errors and I used some workaround inside Page_PreRenderComplete
.
Update to answer comment
In Page_PreRenderComplete
you can process page tree to make replacements. Something like this:
void Page_PreRenderComplete(object sender,EventArgs e)
{
ProcessPageTree((Control)sender); //sender is Page which inherit from Control
}
void ProcessPageTree(Control control) //All server side controls inherit from abstract Control
{
if(control is HyperLink)
{
var hl = control as HyperLink;
hl.Text = hl.Text.Replace("{{something}}", "something new");
}
else if(control is Literal)
{
var ltr = control as Literal;
ltr.Text = ltr.Text.Replace("{{some}}", "something another");
}
if (control.HasControls())
{
foreach(Control c in control.Controls)
{
ProcessPageTree(c);
}
}
}
Upvotes: 1