How to upgrade feature in SharePoint 2010 using Visual Studio

Hi2all!

Please, refer to my revisited post, it contains more solid and working example of upgrading features using visual studio.

Today I'm going to explain how to use new SharePoint 2010 enhancement - feature upgrade. I'll create small example just to show how it works. First of all let's create new Visual Studio project and add new feature named "SomeFeature". Our feature will be install new list instance to site - Tasks list. In feature settings specify version of your feature, it must be set to "1.0.0.0". Deploy you project and make sure that your feature successfully install and new list appear. Its time to upgrade now. There is no command "Upgrade" in Visual Studio, that why we'll create own command using nice CKSDEV plugin. Go to the project settings and create new deployment configuration "UpagradeFeatures". There are three steps in configuration - Recycle IIS Application pool and two steps named "Run PowerShellScrips" from CKSDEV extension.

First script will be update our solution (.wsp file) in configuration database, the second one will find all features that need to be upgraded and call method "Upgrade" on each. Upgrade will be fire only on those features, that have version number is less than appropriate number in configuration database. SPWebApplication class has a method QueryFeatures that returns all features in web application that need to be upgraded.
Here is a code in file UpdateSolution.ps1:

param([string]$solutionPackageName, [string]$solutionPackagePath)
Add-PSSnapin Microsoft.SharePoint.Powershell -EA SilentlyContinue

$solution = Get-SPSolution | where-object {$_.Name -eq $solutionPackageName}
if ($solution -ne $null) {
  if($solution.Deployed -eq $true){
    Write-Host "Updating old version of solution package"
    Update-SPSolution -Identity $solutionPackageName -LiteralPath $solutionPackagePath -Local -GACDeployment
    Write-Host "Solution has been updated"
  }
  else {
    Write-Host "Solution package cannot be updated because it is not currently deployed"  
  }
}

Parameters that I pass to the script - there are the package name(include extension) and path to package file. Using Get-SPSolution cmdlet I get solution, then check if it deployed, then call "Update-SPSolution" cmdlet to update solution at last.
File UpgradeFeature.ps1:

param([string]$featureId, [string]$webAppUrl)
Add-PSSnapin Microsoft.SharePoint.Powershell -EA SilentlyContinue

$featureGuid = New-Object System.Guid($featureId)

$webApp = [Microsoft.SharePoint.Administration.SPWebApplication]::Lookup($webAppUrl)
$features = $webApp.QueryFeatures($featureGuid, $true)

foreach($feature in $features){
  Write-Host ("Updgrading feature in " + $feature.Parent.Url)
  $feature.Upgrade($true)
}

In this script I pass feature ID and url to the web application. Static method "Lookup" returns web application instance, then I call QueryFeatures method to find features that need to be upgraded and call method "Upgrade" on each. Code rather simple as you can see. I made some explanation in past post, how to pass parameters in scripts when using "Run PowerShellScript" deployment step. This is a screen of my project settings:

So, this is our scripts. We also need to make some modifications in feature definition to enforce upgrade work. This is new element in feature definition - "UpgradeActions" When you open your feature in design you not find any settings where you can place upgrade action schema, that's why you need to manually edit .xml feature file, or edit <FeatureName>.Template.xml. All modifications in this file will be merged with original feature definition file. Here is my upgrade actions:

<UpgradeActions ReceiverAssembly="$SharePoint.Project.AssemblyFullName$" ReceiverClass="$SharePoint.Type.3be7c1f1-5a04-4f48-bff3-f658b997138c.FullName$">
    <VersionRange BeginVersion="1.0.0.0" EndVersion="2.0.0.0" >
      
      <ApplyElementManifests>
        <ElementManifest Location="Tasks2\Elements.xml"/>
      </ApplyElementManifests>

      <CustomUpgradeAction Name="UpdateSiteTitle">
        <Parameters>
          <Parameter Name="Title">title 2.0 version</Parameter>
        </Parameters>
      </CustomUpgradeAction>
    </VersionRange>
  </UpgradeActions>

As you can see I use SharePoint replaceble tokens to specify receiver assembly and class. My new  feature adds additional list named "Tasks2" to a site and change title of  site to "title 2.0 version". Consider the fact that all "ApplyElementsManifests" and "CustomUpgradeAction" elements placed inside the "VersionRange", it means that this actions will be appear only when your feature upgrades from 1.0.0.0  to 2.0.0.0 version. In feature receiver I simply get specified parameter and update site title:

public override void FeatureUpgrading(SPFeatureReceiverProperties properties, string upgradeActionName, System.Collections.Generic.IDictionary<string, string> parameters)
        {
            var web = properties.Feature.Parent as SPWeb;
            if(web != null)
            {
                switch (upgradeActionName)
                {
                    case "UpdateSiteTitle":
                        UpdateSiteTitle(web, parameters["Title"]);
                        break;
                    default:break;
                }
            }
        }

        private void UpdateSiteTitle(SPWeb web, string title)
        {
            web.Title = title;
            web.Update();
        }

You can specify as many custom upgrade action as you want, each of them will be fire separate FeatureUpgrading event with upgradeActionName equals to your custom upgrade action name. In feature settings change version to "2.0.0.0" switch to "UpgradeFeatures" deployment configuration and deploy solution. Title of you site must be changed and there is also additional list appears - "Tasks2".
So this is a starting point, using this solution I try to understand what is actually feature upgrade and how to work with it.
You can download source code here (20.23 kb).

Sorry for my English.