Parse an EPiServer XHTML property with Dynamic Content

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

  • 16 September 2009
  • 0

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!