In this post we’ll create a feature which sets property values of the SPWeb instance against which the feature is activated. The feature is designed to be used within custom site defintions to allow the created web site to be configured in ways suitable to the site defintion.
The feature has the following characteristics;
- There are no feature manifests
- The properties to set and their values will be provided using feature defintion properties
- The feature will have a feature receiver
- The feature should be able to set the SPWeb’s object model properties
- The feature should be able to set or create an SPWeb’s property bag properties
Building the Feature.
Create a standard Web scoped feature with a feature receiver class;
<Feature Id="cfb3318a-88bd-45c4-9037-ab3d09cd32b5" Title="Per Web Properties" Description="This feature is used to set Web properties and is intended for use within Site Definitions." Version="12.0.0.0" Hidden="FALSE" Scope="Web" DefaultResourceFile="core" ReceiverAssembly="PerWebProperties, Version=1.0.0.0, Culture=neutral, PublicKeyToken=34303ed68254af5e" ReceiverClass="PerWebProperties.PerWebProperties" xmlns="http://schemas.microsoft.com/sharepoint/"> </Feature>
As you can see there are no feature manifest files. Next write the code for the feature receivers FeatureActivated method;
public override void FeatureActivated(SPFeatureReceiverProperties properties) { var featWeb = (SPWeb)properties.Feature.Parent; var featWebID = featWeb.ID; using (var web = featWeb.Site.OpenWeb(featWebID)) { var propsUpdated = false; foreach (SPFeatureProperty featProperty in properties.Feature.Properties) { if (string.IsNullOrEmpty(featProperty.Name)) continue; if (string.IsNullOrEmpty(featProperty.Value)) continue; var featPropNameParts = featProperty.Name.Split(new[] {':'}, StringSplitOptions.RemoveEmptyEntries); if (featPropNameParts.Length == 1) { // set object model properties switch(featPropNameParts[0].ToLower()) { // special case properties case "locale": { var ietfLocaleString = featProperty.Value; if (!web.Locale.IetfLanguageTag.Equals(ietfLocaleString, StringComparison.OrdinalIgnoreCase)) { var nci = new CultureInfo(ietfLocaleString); web.Locale = nci; } break; } // for non special case properties just use reflection default: { SetWebProperty(web, featPropNameParts[0], featProperty.Value); break; } } } else if (featPropNameParts.Length == 2) { if (featPropNameParts[0].ToLower() == "p") { // Properties (SPPropertyBag) if (web.Properties.ContainsKey(featPropNameParts[1])) web.Properties[featPropNameParts[1]] = featProperty.Value; else { web.Properties.Add(featPropNameParts[1], featProperty.Value); propsUpdated = true; } } } } if (propsUpdated) web.Properties.Update(); web.Update(); } }
The code which sets SPWeb properties with reflection is shown;
private static void SetWebProperty(SPWeb web, string propertyName, string propertyValue) { if (web == null) throw new ArgumentNullException("web"); if (string.IsNullOrEmpty(propertyName)) throw new ArgumentNullException("propertyName"); var t = web.GetType(); if (t == null) throw new Exception("Invalid reflection object"); var pi = t.GetProperty(propertyName); if (pi == null) throw new Exception("Invalid property: " + propertyName); if (!pi.CanWrite) throw new NotSupportedException("Property " + propertyName + " is Read Only!"); try { var ovalue = Convert.ChangeType(propertyValue, pi.PropertyType); pi.SetValue(web, ovalue, null); } catch (Exception ex) { throw new Exception(string.Format("Unable to set property: {0} to: {1}", propertyName, propertyValue), ex); } }
Finally build, package and deploy the solution to the farm.
Using the Feature in a Custom Site Defintion.
To use the feature in a custom site definition add the following snippet to the WebFeatures section of your site defintions Configuration element, obviously setting those properties as appropriate.
<!-- Per Web Properties --> <Feature ID="cfb3318a-88bd-45c4-9037-ab3d09cd32b5"> <Properties xmlns="http://schemas.microsoft.com/sharepoint/"> <Property Key="MasterUrl" Value="/_catalogs/masterpage/default.master"/> <Property Key="CustomMasterUrl" Value="/_catalogs/masterpage/default.master"/> <Property Key="Locale" Value="en-GB"/> <Property Key="p:myCustomProperty" Value="woo hoo, some useless data value"/> </Properties> </Feaure>
You can specify the property name in 2 ways, to specify a property bag property, prefix the property name value with p:
E.g. p:myCustomProperty
To specify an object model property to set, just specify the SPWeb property name;
E.g. MasterUrl
Published by