I have a page that has a bunch of user controls on it. I want to be able to have "macros" or "placeholders" directly in the content that will get replaced in my code. It shouldn't really matter, but I'm using Ektron as my CMS.
Are there any page events that I can hook into to do a string replace on the entire rendered page content, right before it's sent to the client?
UPDATE
Here is the code that I am currently using to accomplish this:
protected override void Render(HtmlTextWriter writer)
{
string content = string.Empty;
using (var stringWriter = new StringWriter())
using (var htmlWriter = new HtmlTextWriter(stringWriter))
{
// render the current page content to our temp writer
base.Render(htmlWriter);
htmlWriter.Close();
// get the content
content = stringWriter.ToString();
}
// replace our placeholders
string newContent = content.Replace("$placeholder1$", "placeholder1 data").Replace("$placeholder2$", "placeholder2 data");
// write the new html to the page
writer.Write(newContent);
}
Have you tried overriding the render method?
protected override void Render(HtmlTextWriter writer)
{
StringBuilder htmlString = new StringBuilder(); // this will hold the string
StringWriter stringWriter = new StringWriter(htmlString);
HtmlTextWriter tmpWriter = new HtmlTextWriter(stringWriter);
Page.Render(tmpWriter);
writer.Flush();
writer.Write(DoReplaceLogic(htmlString.ToString()););
}
I know that this answer is not going to help since you have already solved this prob and moved on. This is just for people who will face a similar problem in the future ;)
There are two approaches you could use.
This is similar to the accepted
answer. But I would recommend
overriding the render method in a
BasePage and deriving all your
templates from this.
Use a HttpModule or the Global.asax and
attach a Filter to the Response
object. To me this make more
aesthetic sense because the "Filter"
property is supposed to help you
filter the output which is exactly
what you want!
BTW, how is it going with Ektron so far? They are driving me crazy for sure!
Have you looked at the PreRender event in the life-cycle?
Before this event occurs:
• The Page object calls EnsureChildControls for
each control and for the page.
• Each
data bound control whose DataSourceID
property is set calls its DataBind
method.
• The PreRender event occurs
for each control on the page. Use the
event to make final changes to the
contents of the page or its controls.
I believe this is the last place you could do something like this. The next event is SaveStateComplete, which according to the documentation has this behavior:
Before this event occurs, ViewState has been saved for the page
and for all controls. Any changes to
the page or controls at this point
will be ignored. Use this event
perform tasks that require view state
to be saved, but that do not make any
changes to controls.
The simplistic answer that comes to mind is to use asp:Literal controls for your "placeholders". You can set their content during page load, or you can hook into the PreRender event and set them then.
It sounds like you might want to have HTML literals within your page and then you can simply replace them with the appropriate content on the Page_Load event.
This will require you to write out HTML code, as opposed to some simple text, but it sounds like you may be injecting your own JavaScript code or the like in there, which this will work great for.