Ref:
http://blogs.msdn.com/b/vesku/archive/2011/07/29/webtemplate-training-materials-lab-4-upgrading-existing-sites-with-feature-versioning.aspx
Exercise 1 – Creating upgrade application page
In this
exercise we will create simple application page to list features, which
could be upgraded. This exercise will familiarize you to feature
framework object model and how we can use that for upgrading features
granularly. Notice that depending on the actual deployment, you might
actually want to upgrade your features using PowerShell, not by adding
this kind of additional application page to site settings page also to
avoid accidental upgrades by other end users.
Task 1 – Adding custom application page to solution
1. Expand
Layouts folder in the Solution Explorer
2. Right click
Contoso.Intranet folder and choose
Add – New Item…
3. Choose
Application Page template and name it as
UpgradePage.aspx

4. Click
Add
5. Locate
ContentPlaceHolder with the Id
PlaceHolderMain
6. Update place holder as in the following code snipped to include two different tables

7.
Save changes
8. Open
Upgradepage.aspx.cs file under the aspx file
9. Add following using statements

10. Add override for
CreateChildIControls method as follows below the
Page_Load method · Notice that we use
QueryFeatures method to query features which can be upgraded

11. Add following
DisplayFeature method below the
CreateChildControls method

12. Add
btnUpgrade_Click event handler below
DisplayFeature method
using System;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.Collections;
using System.Collections.Generic;
using System.Web.UI.WebControls;
namespace TestDWEContentType.Layouts.TestDWEContentType
{
public partial class UpgradePage : LayoutsPageBase
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected override void CreateChildControls()
{
//query features, which have newer versions available
SPFeatureQueryResultCollection features = SPContext.Current.Site.QueryFeatures(SPFeatureScope.Site, true);
IEnumerator<SPFeature> featureEnumerator = features.GetEnumerator();
while (featureEnumerator.MoveNext())
{
SPFeature feature = featureEnumerator.Current;
DisplayFeature(tblFeaturesToUpgrade, feature);
}
//Query all features
features = SPContext.Current.Site.QueryFeatures(SPFeatureScope.Site, false);
featureEnumerator = features.GetEnumerator();
while (featureEnumerator.MoveNext())
{
SPFeature feature = featureEnumerator.Current;
DisplayFeature(tblFeatures, feature);
}
base.CreateChildControls();
}
private void DisplayFeature(Table tbl, SPFeature feature)
{
Label lblFeature = new Label()
{
Text = feature.Definition.DisplayName
};
Label lblFeatureVersion = new Label()
{
Text = feature.Definition.Version.ToString()
};
Label lblFeatureActiveVersion = new Label()
{
Text = feature.Version.ToString()
};
Button btnUpgrade = new Button()
{
Text="Upgrade",
Enabled = feature.Version != feature.Definition.Version
};
btnUpgrade.Attributes.Add("FeatureID",feature.DefinitionId.ToString());
btnUpgrade.Click += new EventHandler(btnUpgrade_Click);
TableRow row = new TableRow();
TableCell cell = new TableCell();
cell.Controls.Add(lblFeature);
row.Cells.Add(cell);
cell = new TableCell();
cell.Controls.Add(lblFeatureVersion);
row.Cells.Add(cell);
cell = new TableCell();
cell.Controls.Add(lblFeatureActiveVersion);
row.Cells.Add(cell);
cell = new TableCell();
cell.Controls.Add(btnUpgrade);
row.Cells.Add(cell);
tbl.Rows.Add(row);
}
void btnUpgrade_Click(object sender, EventArgs e)
{
string featureId = ((Button)sender).Attributes["FeatureID"];
SPFeature feature = SPContext.Current.SiteFeatures[new Guid(featureId)];
feature.Upgrade(false);
}
}
}
13. Right click the
SPIs folder in the solution explorer and choose
Add – New Folder
14. Name folder as
CustomActions
15. Right click
CustomActions folder and choose
Add – New
16. Choose
Empty template and name it as
FeatureUpgradeSiteSettings and click
Add
17. Update the
Elements.xml file for the custom action as follows

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomActionGroup Id="PEIntranetGroup" Description="PE specific links" Title="PF Configuration" Location="Microsoft.SharePoint.SiteSettings" ImageUrl="/_layouts/images/centraladmin_configurationwizards_48x48.png" Sequence="9999" xmlns="http://schemas.microsoft.com/sharepoint/"></CustomActionGroup>
<CustomAction Id="PEIntranetConfigurationLink" Description="Use this functionality to review feature versions activated on the site and to upgrade features." Title="PE Feature Upgrade" GroupId="PEIntranetGroup" Location="Microsoft.SharePoint.SiteSettings" RequireSiteAdministrator="FALSE" Sequence="203" xmlns="http://schemas.microsoft.com/sharepoint/">
<UrlAction Url="~site/_layouts/PEIntranet/UpgradePage.aspx"/>
</CustomAction>
</Elements>
18. Update feature association for the just added custom action
FeatureUpgradeSiteSettings so that it’s activated in the
SiteMainResources feature

19. Open
SiteMainResources feature and use properties window to set the version to 1.0.0.0

20. Right click
Contoso.Intranet and choose
Deploy
21. Move to address
http://intranet.contoso.com
22. Move the
Site Settings from the
Site Actions
23. Click
Site collection features under the
Site Collection Administration
24. Activate
Contoso.Intranet Site Main Resources feature
25. Move back to
Site Settings page and ensure that the
Site Collection Feature Upgrade link is present under the
Contoso Configuration

26. Click
Site Collection Feature Upgrade link is present under the
Contoso Configuration to ensure that code is working properly
- Page should list all activated features in site collection scope and their version
- Notice that look and feel depends on which master page has been enabled for the system pages.
Task 2 – Updating features and content types
1. Move back to
Visual Studio side
2. Expand
SPIs folder, right click
SiteColumns and choose
Add – New Item
3. Choose
Empty Element and name it as
v2Fields

4. Update the Elements.xml as in the following code snipped

5.
Save changes
6. Expand
Features node and open up
Contoso.Intranet Site Main Resources feature
7. Associate the
v2Fields to
Contoso.Intranet Site Main Resources feature. You can use
packaging explorer to ensure the current associations.
- This
is done for new site collections, so that now added field is added
automatically when new sites are created. Steps to modify existing sites
will follow up later in this exercise.

8. Expand
SPIs folder and
ContentTypes folder in the solution explorer
9. Open
Contract content type
element.xml file and review the content – notice that our field is not present and it
should not be added here either
Upgrading content types – what to do and what not to do? |
IMPORTANT
|
You
should NEVER EVER update content type definition which has been already
deployed to any site collection. This would not result outcome you’re
looking for. When we are updating existing content types, we’ll need to
do two different things.
Update initial definition for new site collections – even for this, you should not
update actual ContentType definition, since that would break reference
to it from existing site collections. What we’ll need to do is to add
some code to add newly added field to existing site collection from
feature receiver.
Update existing content types
– Most reliable way to do this also by using code – by adding required
changes to feature upgrade method, which is called when feature is
upgraded to latest version.
We’ll cover both approaches in following steps in this exercise. |
10. Open
Page content type
element.xml file and review the content, notice hat our new field is not present and
should not be added here either

11. Let’s start by handling upgrade scenario for existing site collections. Expand the
SiteMainResources feature node and open up
SiteMainResources.Template.xml file by double clicking it

12.
Update the template file as follows, so that there’s few upgrade
actions to perform, when we upgrade from previous version to newer one
- Notice
that we use one out of the box feature upgrade action and then we’ll
include two custom feature upgrade actions to handle more specific
updates on our existing site collection.

<?xml version="1.0" encoding="utf-8" ?>
<Feature xmlns="http://schemas.microsoft.com/sharepoint/">
<UpgradeActions>
<VersionRange EndVersion="2.0.0.0">
<ApplyElementManifests>
<ElementManifest Location="TestDWESiteColumns\Elements.xml"/>
</ApplyElementManifests>
<CustomUpgradeAction Name="AddFieldToContentType">
<Parameters>
<Parameter Name="FieldId">B8D4ABA4-E4D5-43B0-AEA8-B4C8B6F0AB88</Parameter>
<Parameter Name="ContentTypeId">0x0100D35D88BD185F40439841F4381B9E82FD</Parameter>
<Parameter Name="UpdateChilds">true</Parameter>
</Parameters>
</CustomUpgradeAction>
</VersionRange>
<VersionRange EndVersion="4.0.0.0">
<ApplyElementManifests>
<ElementManifest Location="TestDWESiteColumns\Elements.xml"/>
</ApplyElementManifests>
<CustomUpgradeAction Name="UpdateSiteColumn">
<Parameters>
<Parameter Name="FieldId">B8D4ABA4-E4D5-43B0-AEA8-B4C8B6F0AB88</Parameter>
<Parameter Name="ContentTypeId">0x0100D35D88BD185F40439841F4381B9E82FD</Parameter>
<Parameter Name="UpdateChilds">true</Parameter>
</Parameters>
</CustomUpgradeAction>
</VersionRange>
</UpgradeActions>
</Feature>
13. Update
[PAGEID] and
[CONTRACTID]
stamps in the just copied xml element with the proper identifiers. You
can locate the ID’s from the following locations. These refer to unique
identifiers of the content types in following files:
- [PAGEID] – SPIs – ContentTypes – Page – Elements.xml
- [CONTRACTID] – SPIs – ContentTypes – Contract – Elements.xml
More on feature upgrade options and techniques |
You
can find more information on the feature upgrade options and techniques
from Internet. In this case we used ApplyElementManifest first to
introduce new field to site collection. After that we are using
CustomUpgradeAction element to which we write the required code in
following step – in this case are also using custom upgrade action to
provision newly added fields to existing content type.
There’s
also out of the box element for updating existing content type
declaratively, but since this element have been having some issues in
certain cumulative updates, it’s more reliable to use custom code, which
we will include to our feature receiver. This also gives us additional
change to perform additional confirmation or code validation, if needed
for the code. |
14. Since we will manipulate Publishign object model, we’ll need to add reference to
Microsoft.SharePoint.Pulbishing.dll
15. Right click
References in the
Contoso.Intranet project and choose
Add Reference…

16. Move to
Browse tab and move to folder
C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI
17. Select
Microsoft.SharePoint.Publishing.dll and click
OK
18. Open
SiteMainResources.EventReceiver.cs to see the content of the feature receiver
19. Add following override for
FeatureUpgrading below
FeatureDeactivating method
- Notice
that we place our actual business logic code for updating existing
sites outside of the feature receiver, which gives us possibility to
test that business logic separately without need for feature receiver
deployments etc.
public override void FeatureUpgrading(SPFeatureReceiverProperties properties, string upgradeActionName, System.Collections.Generic.IDictionary<string, string> parameters)
{
if (properties.Feature.Parent is SPSite)
{
SPWeb web = ((SPSite)properties.Feature.Parent).RootWeb;
switch (upgradeActionName)
{
case "AddFieldToContentType":
string fieldId = parameters["FieldId"];
string contentTypeId = parameters["ContentTypeId"];
bool updateChilds = true;
bool flag;
updateChilds = bool.TryParse(parameters["UpdateChilds"], out flag);
UpgradeManager.AddFieldToContentType(web, contentTypeId, fieldId, updateChilds);
break;
case "UpdateSiteColumn":
string sFieldId = parameters["FieldId"];
string sContentTypeId = parameters["ContentTypeId"];
bool sUpdateChilds = true;
bool sFlag;
sUpdateChilds = bool.TryParse(parameters["UpdateChilds"], out sFlag);
UpgradeManager.UpdateSiteColumn(web, sContentTypeId, sFieldId, sUpdateChilds);
break;
}
}
}
20. Let’s continue by adding that required business logic to our project by right clicking
Contoso.Intranet and choose
Add – Folder
21. Rename newly added folder as
ApplicationLogic
22. Right click
ApplicationLogic folder and choose –
Add Item…
23. Choose
Class and name it as
UpgradeManager.cs

24. Your solution should be looking like in following picture
![clip_image002[1] clip_image002[1]](https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_vByHc4ij0YZFDDNdYnaCCvKsF5HGvxede7XR5gRu8j8QvklqehVE9JZ_67p6UY6kHSnud8sic0SGfviNM_-9FHiY-_nMbK9nUpk5mIWC4f2wX6B2kcRGXbfuT4I7P1m-y5oCMv-5Q-Bn_vknSbhz-fPE9bgxzqiQg9pSZTEpYtXY6bz-Kn7mD7EMjIey5974Kfsjk43H4DdjZ1jTwzBySffK8x85V5bP1Sll3qF2Zj5Up5M0VjAf7-vluxn1e50d9WGFgViWdz8D11=s0-d)
25. Open just added
UpgradeManager.cs file
26. Add following
using statements to file

27. Let’s also change the class to be static and include required business logic methods as follows
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Publishing;
using Microsoft.SharePoint.WebPartPages;
using System.Web.UI.WebControls.WebParts;
namespace TestDWEContentType.ApplicationLogic
{
public static class UpgradeManager
{
public static void AddFieldToContentType(SPWeb web, string contentTypeId, string siteColumnId, bool updateChilds)
{
SPContentType type = web.ContentTypes[new SPContentTypeId(contentTypeId)];
type.FieldLinks.Add(new SPFieldLink(web.Fields[new Guid(siteColumnId)]));
type.Update(updateChilds, updateChilds);
}
public static void UpdateSiteColumn(SPWeb web, string contentTypeId, string siteColumnId, bool updateChilds)
{
SPField field = web.Fields[new Guid(siteColumnId)];
field.PushChangesToLists = updateChilds;
field.Update();
}
}
}
28. Before this class can be used in feature receiver, we’ll need to also add
using statement for that, so let’s open
SiteMainResources.EventReceiver.cs to see the content of the feature receiver
29. Add following using statements to file

30. Open
Contoso.Intranet Site Main Resources feature in designer and use properties window to set the version to
2.0.0.0

31. Right click
Contoso.Intranet and choose
Build
- Notice
that until now we’ve only added code for handling upgrade of the
existing structures, we’ll still need to ensure that if new site
collections are created where this site collection scoped feature is
activated, content types will match on latest requirements
32. To handle content type change requirements in proper way, let’s open
SiteMainResources.EventReceiver.cs
one more time. Let’s update the feature activated event as follows –
notice that we add the required code for adding programmatically field
to content types.
- Again
– just to emphasis why we did above add-in to feature activation, not
on xml. This is for newly created site collections, since we should NOT be updating ContentType xml definition anymore, since we have already that used in one site collection in our environment.
33. Update
[PageID] and
[CONTRACTID]
stamps in the just copied xml element with the proper identifiers. You
can locate the ID’s from the following locations. These refer to unique
identifiers of the content types in following files:
- [PAGEID] – SPIs – ContentTypes – Page – Elements.xml
- [CONTRACTID] – SPIs – ContentTypes – Contract – Elements.xml
23. Right click
Contoso.Intranet and choose
Package
- Note. DO NOT DEPLOY PACKAGE DIRECTLY FROM VISUAL STUDIO,
since we will imitate production upgrades in following steps and if you
use Visual Studio, your upgrade option is not available since Visual
Studio will “try to help you” and it reinstalls features using
activate/deactive commands, which doesn’t happen in actual production
deployments.
24. Right click
Contoso.Intranet and choose
Open Folder in File Explorer
25. Move to
bin –
debug sub folder and verify that you have compiled successful
Contoso.Intranet.wsp file, which is the actual solution package to be deployed
26.
Copy current path to clip board, since we need to use that in
PowerShell. If you are using defined guidance, path is following -
C:\StudentWebTemplate\Labs\Contoso.Intranet\Contoso.Intranet\bin\Debug
27. Open
SharePoint 2010 Management Shell from
Start | All Programs | Microsoft SharePoint 2010 Products
28. Run following command in the PowerShell window
- Notice that path depends on your solution structure location
Update-SPSolution
-Identity contoso.intranet.wsp -LiteralPath
"C:\Student\Labs\Contoso.Intranet\Contoso.Intranet\bin\Debug\Contoso.Intranet.wsp"
–GACDeployment |
Upgrade or Re-deploy |
In
this case we used Update-SPSolution cmdlet, but you could also do
retract and deploy commands in PowerShell script. Difference is that
when we use update command, none of the feature installed or uninstalled
methods are executed, but if you have added features to your package,
those don’t get installed either.
If you use
retract – deploy method, feature installed and unistalled commands will
be executed and possible new features are automatically installed. Key
point to notice though that both options don’t activate or deactivate
features in the sites, like Visual Studio does. This is critical
difference between development and production environment deployments. |
29. Run command “
iisreset” in the PowerShell to ensure that updated xml files will be loaded to memory
30. Open Internet Explorer and browse to site
http://intranet.contoso.com
31. Make sure that front page has not been checked out – you can publish it manually before moving forward
- This is just due the code for the feature receiver, which doesn’t have exception handling if the page has been checked out.
32. Move to
Site Settings page from the
Site Actions
33. Click
Site Collection Feature Upgrade link under
Contoso Configuration
34. Notice that the
Contoso.Intranet Site Main Resources feature is listed here as possibility to upgrade

35. Click
Upgrade button
- This will execute the FeatureUpgrading event definitions (code and xml based configurations)
36. Refresh page by pressing [F5] and verify that feature is not anymore listed to be upgrade

37. Move back to
Site Settings page
38. Move to
Site Content Types
39. Click
Contoso.Intranet – Contract and ensure that
Additional details fields has been added to content type
- You
might want to verify successful update also on content type instances
provisioned to existing lists, like pages list. You can do this by
moving to list where content type is used and checking content type
properties from list settings.

40. Move back to front page of the site and verify that web part was successfully added to the page
Upgrading features without custom application page |
| In
this exercise we created custom application page to update feature.
Depending on environment, PowerShell is much more convenient so that you
have full control when upgrade is executed and nobody will upgrade
features accidently just from the browser user interface. |