This post was prompted by a post in the MSDN Forums. Simply put … what order do things happen in the onet.xml?
This may seem like a trivial question .. but if you are writing custom features, it is important (to say vital) that you know whether or not your feature will activate before a list is created or after, or whether or not your files in modules will have been provisioned or not.
The order that I discovered is as follows:
- *<SiteFeatures> in onet.xml
- *Stapled Site Features (stapled using FeatureSiteTemplateAssociation)
- <WebFeature> in onet.xml
- Stapled Web Features (using FeatureSiteTemplateAssociation)
- <Lists> in onet.xml
- <Modules> in onet.xml
* note - obviously Site Features will only activate if you are creating a Site Collection, as opposed to a normal web site
How I worked this out
Well, you can copy the steps yourself, in 8 easy steps:
First off, create a new Custom Site Definition (a simple copy of STS). In my example, I called it MHSTS with a single configuration (#0) and created a WEBTEMP file to register it.
Second, create a new SPFeatureEventReceiver class (in an assembly from a class library). The code in the "FeatureActivated" should be something like this:
// this will let you check which feature is being activated .. so you can work out the order
string strFeature = properties.Definition.DisplayName;
// Add more code to check the SPWeb.Features, SPSite.Features, SPWeb.Lists and SPWeb.Files …
// this will tell you what has been created in the site, and what other features have been activated
Third, create 5 features (the scope is in [ ])
- mhOnetSiteFeature [Site]
- mhStapledSiteFeature [Site]
- mhOnetWebFeature [WEB]
- mhStapledWebFeature [WEB
- mhManualWebFeature [WEB]
Each of these needs to be attached to the same SPFeatureEventReceiver class that we referenced earlier. This allows your debugger to work out which feature is activating … so each time your code steps into breakpoints, you can check the "Feature.Definition" properties and work out which feature is being activated.
Fourth step, create 2 more features which will act as Feature Staplers (using FeatureSiteTemplateAssociation elements).
Fifth.. in your custom site definition (MHSTS) add the following features into the onet.xml:
-
<SiteFeatures>
- mhOnetSiteFeature
- mhWebStapler
-
<WebFeatures>
Sixth; Install all of the features using STSADM, and (in Central Administration) activate the "mhSiteStapler" feature within a test Web Application.
Seventh; Within that Web Application, create a new Site Collection using your new site definition (MHSTS). This should fire off all of your features in the following order;
- mhOnetSiteFeature
- mhStapledSiteFeature
- mhOnetWebFeature
- mhStapledWebFeature
(you can check this by debugging your event handler, and setting a watch on the properties.Definition.DisplayName value)
Now .. if you are keeping a close eye on your debugging window, then you can also start to look at the state of the SPWeb itself. The main thing is that None of the Lists or pages will have been created … at ANY point in this process. This means that <Lists> and <Modules> will not be executed until ALL of your features have activated.
Eighth; Now you can double-check the theory … navigate to your new Site Collection .. and activate your remaining feature manually (mhManualWebFeature).
You should still have your debugging window open .. which should let you know that now (after the site is provisioned) all of the Lists and web pages are now accessible from Code.
Ok .. that's great … errrr … so What ??
Well, this has quite a lot of importance for writing custom features. If you want to write features which automatically manipulate pages and lists then you are going to be a bit stuck, as the lists and pages won't have been created until after your feature activates! (bummer eh? But what you gonna do?)
To get around this problem you really have 2 options:
-
Make your own custom definition. Strip the lists out of the onet.xml, and create ListInstance Features. These can then be created during the feature activation stage, allowing them to be modified by other features that are being activated / stapled.
- Put some While Loops with Thread.Sleep() statements in your code, basically waiting until the lists have been created. This is not a very elegant solution but you don't have much choice if you are trying to use staplers to modify out of the box definitions (or if you don't want to touch the onet.xml).
Thats it ... comments welcome as always :)