Wednesday, February 15, 2012

PageTypeBuilder and EPiServer edit-on-page (DOPE)

So I needed to implement DOPE on a page for a client today. DOPE is the on page editmode of EPiServer where you can edit the content directly on the page without entering edit (or quick edit) mode. This only works if a few conditions are met:


  • Viewstate must be enabled
  • Requestvalidationmode (in the httpruntime element of web.config/system.web) is set to 2.0, only applies if you run your site in .net 4.0
  • You must use the control <EPiServer:Property /> to render your property data.

The problems that directly arise is that <EPiServer:Property> require you to enter a property name to be rendered. This is bad in the sense that we use PageTypeBuilder to create our properties and we want to be able to refactor and whatnot in our code. Now raise your hand everyone of you that have forgotten to update a Codebefore element that had a magic string reference to a EPiServer property after changing the property name.

So to get around that, I found one way that (my colleague Andreas tipped me is similarly implemented in entity framework) uses some reflection and lambda magic to achieve our goal of having no magic strings in codebefore.

We first define our property in codebefore, note that we use a ID instead of the PropertyName magic string property:

<EPiServer:Property runat="server" ID="MainBody" DisplayMissingMessage="False" Editable="True" />

Next, we create a extension method to retrieve the name of a class property:

public static string GetPropertyName<T, TResult>(this T obj, Expression<Func<T, TResult>> property)
where T : TypedPageData
{
var body = (MemberExpression)property.Body;
return body.Member.Name;
}

And finally we connect our property to our control and enable viewstate only when needed, this is done in our page codebehind:

protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (CurrentPage.QueryDistinctAccess(AccessLevel.Edit))
{
EnableViewState = true;
}
MainBody.PropertyName = CurrentPage.GetPropertyName(p => p.MainBody);
}

Now if we refactor our MainBody property in our page type, the text on our page will not be broken until we change the magic string to reflect the new name. Since a property refactoring will also change the lambda expression to retrieve the property name. Pretty neat, huh?


Update:

The extension method above already exists in PageTypeBuilder (in the PageTypeBuilder namespace), so just refer to that namespace and you can use the extension method on any object inheriting PageData.