Mark Ferraz

All MindsharpBlogs

My Links

Archives

Image Galleries

Blog Stats

Mark's Links

Using a Delegate Control Feature to Reconfigure OOTB Site Definitions (aka, The AdditionalPageHead / PropertyBag Trick)

Scenario:

Let’s assume you needed every team site in your SharePoint Server 2007 environment to have some settings set a certain way, be branded, and have some web parts moved around on the default page. Well, traditionally speaking, you had the following supported options:

1.)    Feature Staple in some new custom features (which alone, doesn’t really solve your web part objective)

2.)    Copy the STS site definition and use it as the basis for your own new custom site definition

3.)    Create a new site template for use (which precludes your users from creating a site template of their own in the future)

Each of these options poses some upgradability issues, but none more than the one that most optimally meets your objectives, the custom site definition.

What if you could simply use the OOTB team site definition, which is easily upgradable, reliable, and template-able, but you could still meet each of your objectives, and as a bonus you could even manage the state of configuration over time and apply updates as desired.

The goal of this post is to guide you through the creation of a SharePoint Feature which will provide the following functionality:

1.       Loads a new control on every page without the need for customization of the default.master or application.master

2.       Eliminates the need for a Custom Site Definition by allowing you to perform all the required changes at runtime, starting from an OOTB Site Definition

3.       Tags a site or list library with the version of the changes applied so as to prevent the actions from being re-performed on every page load

4.       Allows for the rolling update of site and list library settings/configurations over time without the need to re-provision sites and without disturbing existing content (unless intended)

We are going to accomplish all of these objectives without:

1.       Creating a Custom Site Definition

2.       Changing any XML Definition files on the server over time

3.       Breaking any of the supportability guidelines established by Microsoft

4.       Creating the additional difficulty associated with Custom Site and List Definitions during upgrade

The key to achieving our goal is the use of assembly based configuration management, which is basically performing your changes through code, via the object model, and tracking the change sets applied to a given object. Sounds easy, right? Well, it is actually, and I’m about to show you how!

Before we get started, lets layout the basic principals which make this approach work within SharePoint:

1.       SharePoint has a rich object model which allows you to perform almost all of the changes required, so it’s fairly straightforward to apply the needed changes via code.

2.       SharePoint’s object model, specifically key objects, contain PropertyBags (or hashtables), which are stored on the object as an array of named Key/Value pairs .  This is important, because Microsoft put these here for extensibility so developers can store and persist information needed by components at runtime.

3.       SharePoint’s Control Feature Element type allows for use to assign a delegate control which can load on every page in SharePoint as an additional control, which allows us to easily bind the firing of our code into the execution pipeline. (more on this in a bit, this is a key piece of the secret sauce of this solution)

4.       SharePoint’s FeatureSiteTemplateAssociation Element type allows for the assignment of added features to be activated upon site creation when sites are created using the specified site definition, in this case the OOTB site definitions.

Alright, so let’s layout how this approach actually performs the changes at runtime. On every page that loads, there is a delegate control called “AdditionalPageHead”. This control is an array control, which allows for multiple instances. This allows for us to have our custom control load alongside the OOTB control. This control is key to our approach because it is within this control that we will use code to perform the configurations changes required.

I know what you are thinking… You want to know if we perform the changes using code on every page load, wouldn’t that slow down things for the user? We wouldn’t want to execute these actions every time the page loads, right?

Right! This is where the PropertyBag enters the picture. Once we have executed our changes, we will add a new key to the PropertyBag of target object. We will have the code that performs the changes check for the existence of this key before it executes our changes. The result is that the code performed changes occur during the very first user request, after which the key is detected pre-venting subsequent loads from re-performing the changes.

Let’s take it even one step further. Let’s say the value of the key we place in the object PropertyBag contains the version of the changes we are applying. Ah-Ha! This allows us to deploy an updated assembly with addition changes at a later time. When this assembly loads with the first user request, it will check for key and find that it is out of date, upon which it will execute the outstanding change sets needed to bring the key version current.

Right on! So what sorts of changes might we want to execute? We could:

-          Remove a sub-site that comes with the OOTB definitions (such as “Report Center” in a Collaboration Portal)

-          Change around web parts on the main page of the definition

-          Create or drop lists, rename lists, etc.

So, why not just use a feature event receiver to do these things? Very good question! You could for some of these things, but in the case of web part changes, page changes, or updates to the provisioned sub-sites in a publishing site, feature events are all firing crazy during creation, making it hard to know for sure that the page on which you want to make the changes even exists yet. Often times, the Microsoft internal provisioning handlers are firing in order to lay down the assets for a specific functionality, which you need to change in some way. That’s why we need to let all of that occur during site creation, and perform our changes during the first user request load. Also, when using feature events, in order to apply updates to the changes, we need to re-activate the feature on every existing site we have, where as this approach allows for farm wide changes to be affected, in addition to allowing for the management of changes over time, even if the control feature is scoped at the site level.

When using this approach, the very first load might take a few more moments, but subsequent loads are not delayed by the single action of checking for the key and then dropping out of execution. Because the changes are performed using elevated privileges, the user making the request is not important, and with the very last action performed being a simple refresh of the page, the initial user is unlikely to even notice that anything even happened, since the first time the see the site rendered, everything has already been changed as required.

Because we are using a feature stapler to bind our control to an OOTB site definition, we need not create our own. Once the control is in place, it will perform our change sets as required upon each deployed update of the control assembly, which is completely supported during the update of a SharePoint Solution. We use a good old case statement to make sure we perform our change sets in order without skipping any of them as we bring an object current.  

Download Sample Visual Studio Project

Please feel free to send any thoughts, comments, or questions to mark@solutionsmark.com

A special Thanks goes out to Subbu (Subramanian S) for his contributions to this post, both in code/collatoral and in conversation...

More to come!

posted on Wednesday, March 12, 2008 11:35 PM

Feedback

# Farm Global Delegate Control Feature Gotcha 8/31/2008 2:03 PM Mark Ferraz


Comments on this post are closed.
Title  
Name  
Url
CAPTCHA
Protected by Clearscreen.SharpHIPEnter the code you see:
Comments