In this article series:
- Feature upgrade (part 1) – fundamentals (this article)
- Feature upgrade (part 2) – a sample to play with
- Feature upgrade (part 3) – introducing SPFeatureUpgrade kit
- Feature upgrade (part 4) – advanced scenarios
- Feature upgrade (part 5) – using PowerShell to upgrade Features
In recent articles I’ve touched on the introduction of versioning and upgradability to the Features framework in SharePoint 2010. I’ve covered this topic recently in conference talks (SharePoint Evolutions) and as a chapter in the forthcoming Real World SharePoint 2010 book – however I also want to cover it to a certain level here, as I’m mindful that not everyone came to the talks or will buy the book. I also want to introduce a tool I’ve published on Codeplex which might be useful if you decide to use Feature upgrade - more on this in the next article.
When would I use Feature upgrade?
Feature upgrade is useful in the following scenarios (though there may be more!):
- To make changes to existing site collections or sites, or something inside – for example:
- Making changes to existing items e.g. adding a new column to a content type/list
- Adding new elements to existing sites e.g. a new list
- Any change which involves doing something to a site using the API e.g. using code to modify the navigation settings for many sites
- To add new functionality into an existing Feature, rather than create a new one – perhaps because that’s the most logical factoring
- Where some functionality will be upgraded several times during it’s lifecycle, possibly in a situation where the changes are not rolled out to every site, or are rolled out at different times
If you’re modifying or expanding on functionality developed using Features (across many sites or just one), then Feature upgrade is likely to be a good vehicle to roll out your changes. This is thanks (in part) to the new QueryFeatures() methods in the API, which provide a convenient collection to iterate over to apply the changes. When the changes themselves are also implemented in code, in the past developers may have put their implementation in the FeatureActivating event and then ensured the Feature is deactivated/reactivated - however this came with baggage, since you might have had other code in there which was never intended to be re-run. Feature upgrade is designed to solve such problems.
What does Feature upgrade look like?
Microsoft added some new XML to the Features framework to support Feature upgrade. When a new version of a Feature is created, this may involve:
- Incrementing the version number of an existing Feature (this is mandatory for Feature upgrade to happen)
- Adding some new XML to define new items for the Feature
- Writing some code to execute in the new FeatureUpgrading event in the Feature receiver
- All of the above
Here’s an example of an upgraded Feature highlighting some of the possibilities:
<?xml version="1.0" encoding="utf-8" ?>
<Feature xmlns="http://schemas.microsoft.com/sharepoint/" Version="1.0.0.0">
<UpgradeActions>
<VersionRange BeginVersion="0.0.0.0" EndVersion="0.9.9.9">
<ApplyElementManifests>
<ElementManifest Location="SomeFunctionality_Iteration2\Elements.xml" />
</ApplyElementManifests>
<AddContentTypeField ContentTypeId="0x010073f25e2ac37846bb8e884770fb7307c7"
FieldId="{536DC46C-DC26-4DB0-A97C-7C21E4362A85}" PushDown="TRUE"/>
<AddContentTypeField ContentTypeId="0x010073f25e2ac37846bb8e884770fb7307c7"
FieldId="{4E7A6719-011A-47EA-B983-A4941D688CA6}" PushDown="TRUE"/>
<CustomUpgradeAction Name="UpdateSomething">
<Parameters>
<Parameter Name="PassSomeValue">This is a string</Parameter>
</Parameters>
</CustomUpgradeAction>
</VersionRange>
</Feature>
[Sidenote] Note that the above XML is actually a subset of the full feature.xml file – when working with Feature upgrade, it is necessary to step outside of the Feature Designer in Visual Studio 2010 and edit the XML files directly (the old-fashioned way!). When doing this the best choice is to allow VS to merge your changes with the XML it is managing. The XML being managed by VS gets merged with your custom XML when the WSP is packaged – if you could this bit of the XML isolated (you can’t, since you never need to), this might look like this:
<Feature Title="Some functionality" Id="cae1f65d-0365-42e9-9907-356c7983e902" Scope="Site">
<ElementManifests>
<ElementManifest Location="SomeFunctionality\Elements.xml" />
<ElementManifest Location="SomeMoreFunctionality\Elements.xml" />
</ElementManifests>
</Feature>
Essentially Visual Studio will still manage our element manifests, but any XML around Feature upgrade needs to be edited by hand. Walking through the box containing the main XML, we can see:
- The Feature has a Version attribute (to be incremented each time the Feature is upgraded)
- A VersionRange element defining the upgrade steps to process for a particular upgrade i.e. when an existing Feature instance within the BeginVersion and EndVersion is upgraded with an updated Feature definition
- An ApplyElementManifests element – this is used to add new elements to an existing Feature. When the Feature is upgraded, any items (e.g. content types, modules etc.) will be provisioned according to the element manifest(s)
- AddContentTypeField element – this is a convenience mechanism for the common task of adding a field to an existing content type (a very common upgrade scenario). Note the PushDown attribute – this is hugely useful as it does the work of pushing down the change from the site content type to all list content types within the site (and therefore, all lists), all without any code.
- CustomUpgradeAction element – this allows the developer to point to some code to run to perform the upgrade actions. It will be common to need this approach, given the vast array of things you might want to do in an upgrade. In terms of the ‘pointing’, in fact the code will always be the FeatureUpgrading method in the receiver, but the value passed in the Name attribute is passed to this method to identify which code to run (along with any parameters). Hence your FeatureUpgrading method is likely to contain a switch statement and would look something like this if it was to match up with the above XML:
public override void FeatureUpgrading(SPFeatureReceiverProperties properties, string upgradeActionName, System.Collections.Generic.IDictionary<string, string> parameters)
{
SPWeb parentWeb = (SPWeb)properties.Feature.Parent;
switch (upgradeActionName)
{
case "UpdateSomething":
string someValue = parameters["PassSomeValue"];
// do some stuff..
break;
default:
break;
}
}
In addition to these possibilities there is one further declarative element – MapFile. MapFile allows you to repoint the location of an uncustomized file, this will literally update the pointer in the database. The precise scenarios where you’d want to use this (as opposed to simply deploying an updated version of the original file) escape my tiny mind unfortunately – the only thing I can think of is that if it allows the repointing to be done at different scopes (e.g. web), in a DelegateControl kind of way, that could be very useful. I’m unable to verify this however as I just cannot get MapFile to work, and neither can others (@jthake) that I know have tried. Oh well.
Taking a step back to look at these tools, it’s easy to think that if you don’t happen to be adding a field to a content type then realistically you’re looking at code. However ApplyElementManifests is often all you need for some scenarios e.g. a set of new fields + a new content type + a new publishing page layout.
Notes
These are some ‘fundamental’ things to know – I’ll discuss some more advanced aspects in a future article:-
- Feature upgrade does NOT happen automatically (including when the Feature is deactivated/reactivated)! The only way to upgrade a Feature is to call SPFeature.Upgrade(), typically in conjunction with one of the QueryFeatures() methods. My tool which I’ll go on to talk about is a custom application page which helps you with this part – note there is no STSADM command, PowerShell cmdlet or user interface to do this out-of-the-box.
- On the VersionRange element, BeginVersion is inclusive but EndVersion is not. In other words, a Feature instance will be upgraded if the current version number is equal to or greater than BeginVersion , and less than EndVersion.
- Upgrade instructions are executed in the order they are defined in the file.
- If a Feature does not have a Version attribute, the version is 0.0.0.0.
- Enabling logging can help diagnose any issues. In the ULS settings, under the ‘SharePoint Foundation’ category, set the following sub-categories to Verbose to see more info:
- Feature Infrastructure
- Fields
- General
- Feature Infrastructure
Summary
SharePoint 2010 introduces additional lifecycle management capabilities with the ability to version and upgrade Features. There are some declarative elements such as ApplyElementManifests and AddContentTypeField, but using the CustomUpgradeAction element allows you to shell out to code where necessary. The only way to actually perform upgrade on a Feature once it has been updated is to call SPFeature.Upgrade() on each instance of the Feature (e.g. in each web) which should be upgraded – new QueryFeatures() methods help you locate Feature instances which can be upgraded. I’ve written a custom application page which helps manage this process, to be discussed next time.