Inconvenient Templated Controls and customized pages in SharePoint 2010

Mavention Templated SiteMapPath control in a Master Page
Using Templated Controls is a great way for separating UI from functionality. Unfortunately as soon as you customize the Master Page or Page Layouts that uses a Templated Control things are likely break. So what is exactly happening behind the scenes and, what’s more important, how should you deal with it?

Templated Controls are the way to go

When building public-facing websites the HTML is the center of the universe. At the end of the day it’s the HTML that has a big influence on the success of your website. By crafting proper HTML you can ensure that your website is accessible for all users and devices, you can optimize its contents for search engines and in many cases you can even improve the perceived performance of your web pages. You can achieve all of this if you construct HTML optimized for the specific needs of your website and its content.

Assuming that you’re following this pattern, of starting from HTML and implementing it into SharePoint, it’s only the matter of time until you find that some of the standard available controls and Web Parts won’t support your HTML. In such cases developers often choose either to build their own controls that produce just the right HTML or to change the HTML to match the output of the standard SharePoint 2010 controls. It’s not that hard to imagine that neither of those choices are great in long term and preferably you would like to have another possibility.

When it comes to building public-facing websites, where the HTML is the foundation of the user experience, Templated Controls are probably the best approach to choose. Because they separate the functionality from the UI you can use one and the same control to build virtually any kind of HTML imaginable. Previously on my blog I’ve showed you how you can leverage the concept of Templated Controls for building menus and breadcrumbs.

Many faces of building websites in SharePoint 2010

When building public-facing websites, or any other solution for that matter, on the SharePoint 2010 platform there are two ways in how you can approach the process: you can choose for a more structured and repeatable process based on automation, Solution Packages and Features or you can leverage the customization capabilities of the SharePoint and move away from the custom development path.

A structured and repeatable approach offers you great control and lowers possible risks. The consequence of using it is however that you will end up spending more time to automate your deployment and test your solution in all the different environments. Customization-based approach on the other hand is great for working in dynamic teams where adjustments or changes have to be done immediately and where they are related to content management rather than business logic.

It’s important to understand that there is no “best practice” and that you should always make educated choice about which approach you choose based on your situation and requirements. You should however be always able to choose out of those two approaches and not be limited to a certain choice.

Inconvenient Templated Controls and customized Master Pages and Page Layouts

Templated Controls allow you to separate the business logic from the UI and with that create truly reusable components: while the business logic is often the same within the whole organization, different teams or brands have very likely their own way of presenting things to the end users.

When working with Templated Controls you can define the presentation layer using Templates. The exact number of those templates depends of course on the control that you are using, but the mechanics is the same for all them. The following code snippet shows an implementation of a breadcrumb using the Mavention Templated SiteMapPath control that I have built recently:

<Mavention:TemplatedSiteMapPath runat="server">  
    <HeaderTemplate><div id="breadcrumbs"></HeaderTemplate>
    <RootNodeTemplate><a href='<%# Eval("Url") %>'>home</a></RootNodeTemplate>
    <NodeTemplate><a href='<%# Eval("Url") %>'><%# Eval("Title") %></a></NodeTemplate>
    <CurrentNodeTemplate><%# Eval("Title") %></CurrentNodeTemplate>
    <SeparatorTemplate> / </SeparatorTemplate>
    <FooterTemplate></div></FooterTemplate>
</Mavention:TemplatedSiteMapPath>  

Here is another control that I have used recently to render meta description:

<Mavention:FieldValue FieldName="MetaDescription" runat="server"><ContentTemplate><meta name="description" content='<%# Eval("FieldValue") %>' /></ContentTemplate></Mavention:FieldValue>  

While both controls work great, as soon as you customize the Master Page you will see the following error message:

The ‘Code blocks are not allowed in this file’ error message

Plan for customization

There is a difference between how SharePoint handles customized and uncustomized Master Pages and Page Layouts. One of those differences is that by default no inline code is allowed on customized pages. As I have just showed you, although some code might work just perfectly on uncustomized pages, it can break as soon as you customize them.

Although you could suppress this security feature by registering a Page Parser Path, it introduces a security risk. As soon as you define a Page Parser Path everyone with write access to the files in that path will be able to include server-side code that could potentially break your entire farm! With that you should be really careful with designing your solutions with dependencies on Page Parser Paths.

The customization capabilities of SharePoint 2010 are very powerful and just because you might not use them at first doesn’t mean you won’t be using them later on. It is therefore important that you take the customization scenarios into account and check if the code that you are using works properly with customized pages. Without this it is only the matter of time until you find yourself facing a choice: not using customization capabilities, even though it might make just perfect sense for that particular scenario, or refactoring all the code that doesn’t work with customized pages. As you can imagine neither of those choices is a great option and if you will eventually refactor the code why not do it in the first place?

Templated Controls and customized Master Pages and Page Layouts – better together

Templated Controls do support customized pages. There are however a few things that you have to take care for to ensure that your code snippets won’t break pages once they are customized.

Using the out-of-the-box

In both examples that I have showed you before I have used content templates based on static HTML calling the Eval method to get the underlying data. It’s the combination of static HTML and Eval that causes the error that we have seen after customizing the Master Page. Because the Eval method is called directly from the content template it’s being considered in-line code which is not allowed on customized pages. In order to solve this issue all you need to do is to ensure that all calls to the Eval method happen from within a server-side control.

If we look at the code samples I have showed you previously, we could refactor the breadcrumb to look as follow:

<Mavention:TemplatedSiteMapPath runat="server">  
    <HeaderTemplate><div id="breadcrumbs"></HeaderTemplate>
    <RootNodeTemplate><asp:Hyperlink NavigateUrl='<%# Eval("Url") %>' Text="home" ID="Link" runat="server" /></RootNodeTemplate>
    <NodeTemplate><asp:Hyperlink NavigateUrl='<%# Eval("Url") %>' Text='<%# Eval("Title") %>' ID="Link" runat="server" /></NodeTemplate>
    <CurrentNodeTemplate><asp:Literal Text='<%# Eval("Title") %>' ID="Node" runat="server" /></CurrentNodeTemplate>
    <SeparatorTemplate> / </SeparatorTemplate>
    <FooterTemplate></div></FooterTemplate>
</Mavention:TemplatedSiteMapPath>  

By replacing static HTML with ASP.NET controls we can work around the security feature and have our breadcrumbs work both with uncustomized and customized pages:

Breadcrumbs displayed on a Publishing Page in SharePoint 2010

As for refactoring the second control – the meta description tag you could use the HtmlMeta control that is a part of the ASP.NET framework:

<Mavention:FieldValue runat="server" FieldName="MetaDescription"><ContentTemplate><asp:HtmlMeta Name="description" Content='<%# Eval("FieldValue") %>' ID="MetaDescription" runat="server" /></ContentTemplate></Mavention:FieldValue>  

The only downside of this approach is that because we have to specify the ID for the HtmlMeta control the ID will be added to the output HTML and we will end up with HTML similar to following:

<meta id="ctl00_ctl01_ctl00_MetaDescription" name="description" content="Meta description 123" />  

Although it’s still valid (X)HTML the id attribute is somewhat pointless yet necessary from the ASP.NET perspective.

Another approach that you might consider is somewhat more complex to come up with and to manage but it gives you some more control of the output HTML:

<Mavention:FieldValue runat="server" FieldName="MetaDescription"><ContentTemplate><meta name="description" content="<asp:Literal Text='<%# Eval(&quot;FieldValue&quot;) %>' runat='server' ID='FieldValue' />" /></ContentTemplate></Mavention:FieldValue>  

As you can see we still use static HTML here but in the content attribute we inject the ASP.NET Literal control to have the binding executed in the context of a server control. The biggest challenge in this approach is trying to follow the code and having all the quotes, especially when they are nested, in the right place.

Building custom controls

Although ASP.NET provides you with many controls that should be sufficient for most scenarios, there are situations when you might want that extra bit of control of the output HTML: after all this is exactly the reason why we chose for Templated Controls in the first place. In such cases you have two options: you can build your own custom controls or using an alternative templating mechanism.

Building your own set of custom controls is not that complex and requires no new skills other than what you already can, assuming you are a SharePoint developer. Unfortunately it undermines the whole concept of using Templated Controls since custom control have to have at least partial knowledge about the HTML that they are supposed to render and with that it’s very likely that you won’t be able to reuse them with other solutions.

Another thing that you could do, and that would give you full control of the output HTML is to use a templating mechanism other than the default binding, for example:

<Mavention:FieldValue runat="server" FieldName="MetaDescription" UseStringTemplateRendering="true"><ContentTemplate><meta name="description" content="$FieldValue$" /></ContentTemplate></Mavention:FieldValue>  

Notice how the call to the Eval method has been replaced with a custom $FieldValue$ token. Also to notify our control that we want to use the alternative templating method we have set the UseStringTemplateRendering property to true. During the rendering stage of the process the control will check if it should use the standard or the string-based rendering process and if the later is the case, it will basically do a string replace on all registered parameters which in this case is $FieldValue$.

protected override void Render(HtmlTextWriter writer) {  
    if (UseStringTemplateRendering) {
        if (FieldValue != null) {
            StringBuilder sb = new StringBuilder();
            using (StringWriter sw = new StringWriter(sb)) {
                using (HtmlTextWriter htw = new HtmlTextWriter(sw)) {
                    base.Render(htw);
                }
            }

            writer.Write(sb.ToString().Replace("$FieldValue$", FieldValue as string));
        }
    }
    else {
        base.Render(writer);
    }
}

Because no ASP.NET bindings are used we can now support both uncustomized and customized pages and have full control of the output HTML which is essential if you want to build public facing websites on the SharePoint 2010 platform and to have HTML to be leading in the process.

Summary

Templated Controls are a great way for separating the UI from the code and creating reusable components that support every kind of HTML markup. Unfortunately because there is a difference in how SharePoint treats uncustomized and customized pages, it’s challenging to work with Templated Controls and support both types of pages. In such cases using an alternative templating approach is often the best choice that offers the most flexibility and control over the output HTML.

Comments

comments powered by Disqus