Wednesday, May 18, 2011

Learnings about upgrading elements with SharePoint 2010

Doing the right thing and deploying all of my project elements as features and solutions has led to some interesting behaviors when trying to change certain items such as:

  • Master Pages
  • Page Layouts
  • Content Types
  • CSS
  • Javascript

I experienced behaviors such as changes to Master Pages and page layouts not appearing on my site or content types not updating in lists even though I had updated the Site level content type.

The following summarises some of my learning while looking into why these things were happening.

Let’s start with some basic concepts

Ghosting/Unghosting

Ghosting and unghosting is now referred to as Customizing and Uncustomizing.

Basically it means that if I deploy an item via a solution onto the SharePoint file system, I then create an entry in a list such as the Master page Gallery which references that item on the file system. So it acts like a pointer.

When I deploy an update to the file on the file system, it is automatically used from all of the entries that point to this. So this is what ‘Ghosted’ or ‘ Uncustomized’ means.

As soon as you edit the file through the SharePoint or SharePoint designer, SharePoint breaks the pointer to the file on the file system and copies it to the database. So now the file is ‘Unghosted’ or ‘Customized’.

If there are changes to the file on the file system, these will not be reflected for the entries that are ‘Unghosted’.

_Layouts

When we deploy files to the Layouts mapped folder, these are then available to any site in SharePoint through a virtual URL of http://<server>/<site>/_layouts/<folder>/<file>. Files in the layouts folder don’t have a reference in a list or library so they can’t be ghosted.

Site Columns and Content Types

When we deploy site columns and content types, usually they will be in the root of the site collection.

Use this page to create and manage content types declared on this site and all parent sites. Content types visible on this page are available for use on this site and its subsites.” 

When you use the content type in a list, it creates a child content type of the one in the root.

This means that if you update the parent content type, you may want to “push down” those changes to the child content types. So for example, you might add a new site column to a content type and want it to appear in the lists using that content type.

Making Changes

So the question then becomes, what happens when I want to make changes to my elements after they were initially deployed and perhaps activated by a feature?

Master pages and Page Layouts.

Let’s say that we have a Solution and Feature to deploy our master page and page layout as a Farm feature scoped at the site collection level.

The solution is deployed and the feature activated and the list items created in the Master Page gallery pointing to the files on the file system. So these are uncustomized or ghosted.

I can make changes to the master page or page layout and execute an Update-SPSolution to deploy the changes to the file system. Do not expect a change to the modified date in the master page gallery as the list items themselves have not changed. However, the changes should immediately be reflected on the site.

What can go wrong?

Once you are using a page layout you cannot delete it from the master page gallery. So if you want to change it, you can by the above method, but if you deactivate the feature and try to retract the solution, the page layout will not be removed.

One thing I have seen a lot, is a page layout not updating as expected through a solution upgrade. It seems that SharePoint thinks that the page layout has been customized even though you may not think that it has. It also may not appear to be customized in SharePoint Designer.

One of the easiest ways of making sure that any file is not customized is to use Gary Lapointe’s stsadm commands. This post by Simon Doy describes this nicely.

These commands allow you to view which files are customized and then allows you to re-ghost them:

 

More about Solution Upgrade

Microsoft describe the two ways to Upgrade a Farm Solution in this post. It describes ‘Replacement’ which is where a solution is retracted and re-deployed, and ‘Update’.

The article states that the Replacement method “must be used if the new version of the solution differs from the installed version in any of the following ways.

  • The new version removes a Feature that was in the old version or adds a Feature that was not in the old version.

  • The new version changes the ID of a Feature.

  • The new version changes the scope of a Feature.

  • The new version has a changed version of a Feature Receiver.

  • The new version adds a new elements.xml file, removes an elements.xml file, or changes the contents of an existing elements.xml file.

  • The new version adds a new Property element to a Feature.xml file, removes a Property element from a Feature.xml file or changes the value of a Property element in a Feature.xml file.”

So, once you package your changes, you should be able to do one of the following:

Issue the Update-SPSolution powershell command to deploy it.

For example:

Update-SPSolution -Identity contoso_solution.wsp -LiteralPath c:\contoso_solution_v2.wsp –GACDeployment
Or
Retract and redeploy your solution package.
For example:

clear
Uninstall-SPSolution –Identity <solution name>.wsp

clear
Remove-SPSolution -Identity <solution name>..wsp

clear
Add-SPSolution –LiteralPath <path>\<solution name>.wsp

clear
Install-SPSolution -Identity <solution name>.wsp -GACDeployment

What can go wrong?

While I was investigating this, I tried creating a Feature Receiver to run an UpgradeAction. It took me a little while to work out why it wasn’t firing. The reason was that I needed to use the Replacement method because I had created a Feature Receiver which didn’t previously exists. I assume this equates to the “The new version has a changed version of a Feature Receiver”.

Once I retracted and redeployed, then I could get my FeatureReceiver to work when performing a feature upgrade.

Also, you need to be aware that if you retract and remove a solution, the files will be removed from the file system and your site may break until you redeploy it.

Feature Upgrade

There are quite a lot of good articles and videos on Feature Upgrades with SharePoint 2010. One of the most comprehensive is this series from Chris O’Brien. Chris has also written a solution to allow you to upgrade features via the UI in Central Admin or through Powershell.

I also discovered that you can Upgrade a feature directly from Powershell without Chris’ solution.

$site = get-spsite http://sharepoint/sites/ce2
$web=$site.RootWeb

$enabledfeature = $web.Features | where {$_.DefinitionId -eq “b6f54487-b222-4536-8d4b-3bef94283ddb” }

if($enabledfeature)
{
    $enabledfeature.Upgrade($true)
}

What can go wrong?

I found a few issues as I was working through this. One was described above, where my new Feature Receiver and FeatureUpgrade method would not fire.

Another was to do with sequencing. I declaratively created new site columns and deployed a new elements.xml file.

The first time I ran the feature upgrade, it failed because I had the CustomUpgradeAction declared before the ApplyElementsManifest. This was because I was referencing the site columns in the CustomUpgradeAction that I declared in the elements.xml. Obvious I suppose, but worth noting that you need to sequence the UpgradeActions correctly.

<?xml version="1.0" encoding="utf-8" ?>
<Feature xmlns="http://schemas.microsoft.com/sharepoint/" Version="3.9.0.0">
  <UpgradeActions>
    <VersionRange BeginVersion="0.0.0.0" EndVersion="3.8.0.0">
      <AddContentTypeField/>
       <ApplyElementManifests>
        <ElementManifest Location="UpgradeTest\Elements.xml"/>
      </ApplyElementManifests>
     <CustomUpgradeAction Name="AnnouncementsUpdate">
        <Parameters>
          <Parameter Name="Test">Whatever</Parameter>
        </Parameters>
      </CustomUpgradeAction>
    </VersionRange>
  </UpgradeActions>
</Feature>

Upgrading Site Columns and Content Types

This was a bit perplexing for a while. The FeatureUpgrade allows us to add additional site columns to a content type and Push Down the changes to child content types and lists. We can either do this declaratively using the AddContentTypeField option or through code.

For example:

public override void FeatureUpgrading(SPFeatureReceiverProperties properties, string upgradeActionName, System.Collections.Generic.IDictionary<string, string> parameters)
   {
       switch (upgradeActionName) {
           case "AnnouncementsUpdate":
                 UpgradeAnnouncements((SPWeb)properties.Feature.Parent);
               break;
           default:
               break;      
       }
   }

   private void UpgradeAnnouncements(SPWeb parentWeb){
       try
       {           SPContentType announcements = parentWeb.ContentTypes["TestAnnouncement"];
           SPFieldLink upgradeTest1 = new SPFieldLink(parentWeb.AvailableFields["UpgradeTest"]);
           SPFieldLink upgradeTest2 = new SPFieldLink(parentWeb.AvailableFields["UpgradeTest2"]);
           SPFieldLink upgradeTest3 = new SPFieldLink(parentWeb.AvailableFields["UpgradeTest3"]);
           announcements.FieldLinks.Add(upgradeTest1);
           announcements.FieldLinks.Add(upgradeTest2);
           announcements.FieldLinks.Add(upgradeTest3);
           announcements.Update(true);
       }
       catch (Exception ex)
       {
           throw;
       }
   }

What can go wrong?

The most common thing that seems to go wrong seems to be to do with pushing changes down to existing lists and child content types.

When specifying the ‘PushDown’ option it does not always seem to work. This can be quite frustrating. I found that the easiest way to overcome this was again using one of Gary Lapointe’s stsadm commands to force the changes to propagate:

stsadm -o gl-propagatecontenttype -url "http://sharepoint/sites/ce2" -contenttype "Announcement"

I am sure there are other scenarios and element types not covered here, but this hopefully might help some people to overcome some of the frustrations when upgrading elements of their solutions.

Other useful links

http://blogs.msdn.com/b/sharepointdeveloperdocs/

http://sisharepoint.wordpress.com/2010/01/21/using-the-featureupgrading-event-to-upgrade-features-sharepoint-2010/

http://dirkvandenberghe.com/2009/03/24/how-to-ghost-back-page-layouts.html

del.icio.us Tags: