Creating your own wrapper controls in SharePoint 2007
We all know more or less the SPSecurityTrimmedControl. It basically allows you to display its contents conditionally depending on the permissions of the current user. It is definitely a great piece of engineering and very helpful in various scenarios but what if it’s just not enough and you need either to customize it or to create your own wrapper?
Being able to conditionally display content allows you to better control the HTML output of your web pages. SharePoint 2007 is a very scalable and flexible platform which makes it possible to create solutions for various business cases, but to be able to provide that level of flexibility, SharePoint sends a lot of resources together with the response - not always checking whether you’re using them or not. Being able to control the output and rendering it conditionally gives you the great power of being in control of your HTML which is very important for the performance and accessibility of Internet facing web sites built upon SharePoint 2007.
The SPSecurityTrimmedControl is an out of the box available wrapper control which allows you to conditionally display its contents depending on the permissions of the current user. Probably the most common usage scenario is hiding the Site Actions menu and the Publishing Console from anonymous users:
<SharePoint:SPSecurityTrimmedControl ID="SPSecurityTrimmedControl1"
PermissionsString="BrowseDirectories" runat="server">
<PublishingSiteAction:SiteActionMenu runat="server" />
<wssuc:Welcome id="explitLogout" runat="server" />
<PublishingWebControls:AuthoringContainer ID="authoringcontrols"
runat="server">
<PublishingConsole:Console runat="server" />
</PublishingWebControls:AuthoringContainer>
</SharePoint:SPSecurityTrimmedControl>
SharePoint 2007 uses Security Trimming which creates the User Interface (menu options, links, etc.) based on the current user’s permissions. So is the SPSecurityTrimmedControl exactly the same as the SharePoint Security Trimming? No, it’s not. What the SPSecurityTrimmedControl does, is it determines whether the current user has enough permissions to access the contents of the SPSecurityTrimmedControl. If he doesn’t, the contents of the SPSecurityTrimmedControl will nog get parsed by ASP.NET and you will not see even a bit of HTML coming from that content in the output. So it’s definitely a great way to optimize the output of your web pages. But what if checking the permissions doesn’t provide you enough choice?
There are many other situations you could think of when SPSecurityTrimmedControl is not enough. First of all, imagine that you want to display some extra guidelines for the editors about editing a Publishing Page they are editing. Although you might give them some extra permissions, which would distinguish them from other groups, you could use a custom wrapper control which would display its contents based on the status of the form. You can read the status of the form by accessing the FormContext property of SPContext and then reading the status by accessing the SPFormContext.FormMode property.
Another scenario when you could want to create a custom wrapper control would be trying to conditionally display content on web sites using multiple authentication providers. Imagine that the webmasters and editors work on the staging environment using the Active Directory Authentication and then there is the production environment: most of it is available to anonymous visitors but there are some pages accessible by users authenticated using Forms Based Authentication (FBA). As soon as these users log in, they are not anonymous anymore. Of course it all depends on the permissions you will give them, but it just might be the case that the permissions of these FBA authenticated users and some of the editors might be the same. How to keep the ability of conditionally displaying some content in such situation?
Creating a custom wrapper control
Creating custom wrapper controls is not really difficult. Most of the time implementing the logic of displaying or hiding the contents of your custom wrapper control will be the most difficult part.
A wrapper control is nothing else than a regular ASP.NET custom control:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace Imtech.SharePoint.Solution.Controls
{
[ToolboxData("<{0}:CustomWrapperControl runat=server>
</{0}:CustomWrapperControl>")]
public class CustomWrapperControl : WebControl
{
private bool enabled = true;
protected override void Render(HtmlTextWriter writer)
{
if (enabled)
base.Render(writer);
}
}
}
Because we want the contents of the wrapper to display conditionally, let’s add the enabled variable which will determine whether the contents should be rendered or not. Because we want the wrapper to display its contents only and nothing else, we override the Render method instead of the RenderContents method for example. Andrew Connell has recently wrote a good article about making the choice between overriding the RenderContents and Render methods.
Anyway if you use that wrapper right now to conditionally display its contents:
<Imtech:CustomWrapperControl runat="server">
<asp:Literal ID="Literal1" Text="Hello World from Wrapper"
runat="server" />
</Imtech:CustomWrapperControl>
you will get an error:
So far we have created a regular ASP.NET custom control. To actually turn it into a wrapper control we need to add one more thing: the System.Web.UI.ParseChildrenAttribute. The value of the ParseChildren attribute determines how the contents of the custom controls should be parsed: as one of its Properties or using the associated ControlBuilder. As soon as we add the ParseChildren(false) attribute to the CustomWrapperControl class, its contents will not get parsed as Properties of the wrapper control: a wrapper control is born. It’s up to you now to implement the logic required to determine whether the contents of the control should be rendered or not.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace Imtech.SharePoint.Solution.Controls
{
[ToolboxData("<{0}:CustomWrapperControl runat=server>
</{0}:CustomWrapperControl>")]
[ParseChildren(false)]
public class CustomWrapperControl : WebControl
{
private bool enabled = true;
protected override void Render(HtmlTextWriter writer)
{
if (enabled)
base.Render(writer);
}
}
}
Summary
The goal of wrapper controls is to display their contents conditionally. In many scenarios, especially if it’s about controls you have created yourself, you could implement the same logic inside the controls. Unfortunately it is a poor solution if you consider the reusability of your controls. Determining whether a control should be rendered or not is something that depends on the particular project and its requirements and not on the control itself and should be therefore kept outside the control. Creating custom wrapper controls is an example of extensibility of the ASP.NET framework.
Technorati Tags: SharePoint, SharePoint 2007, MOSS 2007, MOSS