Render Dynamic Content without the Property control
Outputting EPiServer property values are often done using the EPiServer Property control:
<EPiServer:Property PropertyName="MainBody" runat="server" />
Using the Property control will render XHTML properties correctly (obviously), including those that include Dynamic Content. But sometimes we just want to get our hands on the actual markup – and that’s where it gets a bit tricky!
If we get the property value through a PageData object’s property collection…
string body = (string)page["MainBody"];
…we get the raw property value as it is stored by EPiServer and the Dynamic Content parts look something like this:
<span
contenteditable="false"
style="border: 1px solid rgb(17, 17, 17); padding: 3px; background-color: rgb(248, 237, 164);"
class="dynamiccontent"
disabled="disabled"
state="U0VCIHZpZGVvc3xodHRwOi8vd3d3LnlvdXR1YmUuY29tL3YvMW9LSm1CVVhqSVEmZj11c2VyX3VwbG9hZHMmYXBwPXlvdXR1YmVfZ2RhdGE="
dynamicclass="YouTube video"
classid="b30218a7-77fc-43dd-a844-81935aa9b35e">
{DynamicContent:YouTube video}
</span>
If we render this markup we only get this Dynamic Content placeholder instead of the actual markup:
Not quite what we want. So - it’s workaround time!
Parsing an XHTML property with Dynamic Content
My workaround consists of two things: a method for parsing an XHTML property which contains Dynamic Content, and a slight modification of existing Dynamic Content controls to allow them to render without a PageBase context.
Code for parsing the Dynamic Content
This method doesn’t really parse anything by itself, instead it uses a Property control object to do the rendering for us (so I wasn’t really telling the truth when I said we’d do the parsing without a Property control):
/// <summary>
/// Used to parse an XHTML property which includes Dynamic Content
/// </summary>
/// <param name="page">The page containing the XHTML property</param>
/// <param name="propertyName">The name of the HTML property</param>
/// <returns>Markup ready to be rendered</returns>
public static string ParseHtmlProperty(PageData page, string propertyName)
{
// Create a Property control which will parse the XHTML value for us
PropertyLongStringControl ctrl = new PropertyLongStringControl();
// Set the PropertyData to the property we want to parse
ctrl.PropertyData=page.Property[propertyName];
// Initialize the Property control
ctrl.SetupControl();
// Create a string writer...
StringWriter sw = new StringWriter();
// ...and an HtmlTextWriter using that string writer
HtmlTextWriter htw = new HtmlTextWriter(sw);
// Render the Property control to get the markup
ctrl.RenderControl(htw);
// Return the parsed markup
return sw.ToString();
}
Modifying our Dynamic Content to render without PageBase
The Dynamic Content controls in my case had RendersWithControl set to true.
In order for them to render correctly even without a PageBase context I had to modify the GetControl method like so:
public Control GetControl(PageBase hostPage)
{
try
{
if (hostPage==null)
hostPage=(HttpContext.Current.Handler as PageBase);
// Return dynamic content controls
return (MyControl)hostPage.LoadControl("/DynamicContent/MyControl.ascx")
}
}
The result
Using the helper method we can now output the resulting markup like this:
Page.Controls.Add(new Literal()
{
Text = Global.ParseHtmlProperty(myPageData,"MyProperty")
});
Instead of the little placeholder we now get the complete markup for the Dynamic Content (a YouTube video in this case):
Disclaimer
It took me about two hours of reflection, trial-and-error, and wall-banging to come up with this solution, so it’s quite possible that it isn’t the prettiest workaround… :) It is also seriously untested! Any feedback is greatly appreciated, as always!