Once in a while you may be faced with a task to perform custom actions on a site after it was created from a template. One of the most common reasons is a necessity to configure a security baseline for the site by adding cross-site groups and securing lists. Configuring web parts with custom data, changing list column default values, or virtually any other provisioning-time customization shall require that your custom code is ran after the new site is created and content settings have been applied to it from a site definition or a template.
Custom provisioning web forms, ExecuteUrl were a staple in WSS v2 implementations. In v3, Web feature stapling and direct feature activation in a WebFeatures element seem to work great with the exception that event sinks get called prior to lists and web parts included into an ONET.XML module being created. Therefore, your custom code does not get a chance to work with list settings or modify/add web parts to files that were not yet instantiated.
Enter custom site provisioning with a SPWebProvisioningProvider –based class. WSS v3 product team seems to have added this facility to support advanced MOSS templates, such as the Collaboration and Publishing Portals, and the Records Repository. To review, take a peek at the webtempsps.xml and webtempoffile.xml files in the Web Server Extensions\ 12 \TEMPLATE\1033\XML folder and pay attention to the ProvisionAssembly and ProvisionClass, attributes. It would seem that the SPWeb.ApplyWebTemplate() method overloads check whether a given web template has the above custom provisioning attributes defined and allow the custom class to control the provisioning process in lieu of the standard code for applying site definitions or templates.
To implement your custom provisioner, follow the following simple steps:
1) Create a new DLL project, compile and push to GAC. Base your sample on the code below:
namespace TestProvisioner { public class ProvisionerClass : Microsoft.SharePoint.SPWebProvisioningProvider { public override void Provision(SPWebProvisioningProperties props) { SPWeb web = props.Web; web.ApplyWebTemplate("STS#1"); //apply a template to the web web.RoleDefinitions.BreakInheritance(true, false); //add additional role assignments here and perform other custom tasks web.Update(); } } }
2) Create your custom webtempl*.xml file with Configuration and Template entries:
<Templates xmlns:ows="Microsoft SharePoint"> <Template Name="TEST" ID="1590"> <Configuration ID="1" Title="Custom Site" Hidden="FALSE" Description="" DisplayCategory="Test Provisioner" ProvisionAssembly="TestProvisioner, Version=1.0.0.0, Culture=Netural PublicKeyToken=A734583A6378438" ProvisionClass="TestProvisioner.ProvisionerClass" ProvisionData=" "> </Configuration> </Template> </Templates>
Here: existence of the TEST folder, containing the physical ONET.XML file nor the configuration therein seem to matter.
3) Reset the application pool for your WSS application or IISRESET
4) Test by creating your test site.
The behaviour of your custom provisioner may be controlled by parameterising it through the ProvisionData attribute. Your event sink accesses the custom data value through the SPWebProvisioningProperties.Data property. It is up to your code to define what the attribute contains, however, much like with MOSS templates, a path to an XML script file seems like a most logical use. For simpler cases, simply storing a web template name, which shall be applied to the new site may be sufficient