Parse an EPiServer XHTML property with Dynamic Content

This article was migrated from an older iteration of our website, and it could deviate in design and functionality.


This post explains how to parse XHTML which contains dynamic content in EPiServer so that we can retrieve the actual markup.

Estimated read time : 6 minutes

Jump to

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:

Dynamic Content placeholder when rendering XHTML value

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):

YouTube video as Dynamic Content in EPiServer

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!