Showing posts with label SPFeatureReceiver. Show all posts
Showing posts with label SPFeatureReceiver. Show all posts

Friday, May 7, 2010

Dangling SharePoint Features and Files at Upgrade

I recently upgraded from SharePoint 2010 RC1 to SharePoint 2010 RTM on my development machine.  Being a development machine there were several old projects that had been ripped from SharePoint without deactivating the features.  SharePoint tends to swallow these problems – although they show up in the logs.  Upgrade, on the other hand, is blocked by these problems.

I received several errors at upgrade time including errors like

[OWSTIMER] [SPContentDatabaseSequence] [ERROR] [5/6/2010 1:10:30 PM]: Found a missing feature Id = [11d1f820-10d9-48c9-bc44-4ae4439be635], Name = [FeatureName], Description = [], Install Location = [PackageName_FeatureName]

And

[OWSTIMER] [SPContentDatabaseSequence] [WARNING] [5/6/2010 1:10:31 PM]: File [Features\ PackageName_FeatureName \ModuleName\Files\Custom.css] is referenced [1] times in the database [WSS_Content], but is not installed on the current farm. Please install any feature/solution which contains this file.

[OWSTIMER] [SPContentDatabaseSequence] [WARNING] [5/6/2010 1:10:31 PM]: One or more setup files are referenced in the database [WSS_Content], but are not installed on the current farm. Please install any feature or solution which contains these files.

I was not surprised by the first error.  I had removed features without deactivating them, and how could psconfig know how to upgrade them if they no longer existed in the farm.  The second set of errors was unexpected and spoke to a new layer upgrade I had not expected.  The files that it was complaining about were documents that I have deployed to libraries using SharePoint modules.  The modules were gone, but the libraries existed.  How did it know that the document came from a SharePoint module and why does it care?

Further examination of the dbo.AllDocs table in SQL Server Management Studio turned up that it contains the columns “SetupPath” and “SetupPathVersion” which can tie a document in a library back to a feature deployment action.  Apparently, one of the activities psconfig does during upgrade is to check if the file in the library should be replaced by a newer version that had been deployed into the 14 hive.  I am not sure if that is done by comparing the matching SPPersistedFile within the config database or by comparing the document with the actual file on disk.   The SetupPathVersion is a tinyint so it is hard to understand what it maps against.

Regardless of the algorithm, it is pretty clear what upgrade was attempting to do.  This adds a new item to my list of upgrade functions that psconfig executes:

+ Check SPPersistedObject versions in the config database and call the IUpgradable and IUpgradable2 interfaces to get them to upgrade as needed.

+ Traverse the SPSite-SPWeb trees in the farm and upgrade each feature instance using the feature upgrade CAML along with any SPFeatureReceiver.FeatureUpgrading methods.

+ Examine all Library documents, determining if any come from features.  If they do come from features, check to see if a new version needs to be loaded from the 14 hive.

In my situation the upgrade failed and directed me to fix errors (shown in log) and try again. The error may say: “Please install any feature or solution which contains these files.” I thought this would be rather risky with my half upgraded farm. To complete my upgrade, I went to SQL Management Studio and deleted the problematic data from my content database.  I queried the dbo.Features table based on the feature IDs in the log and deleted those rows.  I queried the dbo.AllDocs table based on the SetupPath of files found in the log and deleted those rows.  I kicked off:

PS> psconfig -cmd upgrade -inplace b2b

Which completed successfully and I was upgraded.

 

Thursday, November 5, 2009

Features are Versioned and Upgradable on SharePoint 2010

One of the big sticking points with SharePoint 2007 was that Microsoft failed to adequately address was how to update between versions of third party SharePoint applications. Microsoft has addressed much of this introduction of feature versioning in 2010.

Starting with SharePoint 2010, the versions of all features activated are stored. Farm and web application features versions are stored in the config database. Site collection (SPSite) and site (SPWeb) features versions are stored in the content database. Features shipped without version numbers default to version 0.0.0.0.

With the in-place upgrade process provided in psconfig.exe, the farm is scanned and the versions of all features activated are compared with the versions of the feature definitions installed. Any active feature that is not up to the current feature definition (SPFeatureDefinition) version has the opportunity to upgrade. How that upgrade occurs depends on a new block of CAML XML in the feature definition under the new UpgradeActions element.

There are several types of UpgradeActions. They include CustomUpgradeAction, ApplyElementManifests, AddContentTypeField, and MapFile. The most flexible of these is CustomUpgradeAction for which you can assign a SPFeatureReceiver. When you do that it will invoke a new method FeatureUpgrading on the SPFeatureReceiver.

Some upgrade code paths must always run. An example of this would be having a base schema for a content type which never changes (because it was released in the past), but always AddContentTypeField regardless of whether deploymenting a new current version or an upgrading to the current version.

At other times, you must use the VersionRange element. This element specifies the affectivity of the upgrade code. An example would be a new module added to older versions.

Over the next few days I will post some examples of using feature upgrade.

Monday, April 13, 2009

Deployment of ASP Resources

Resource files referenced directly in ASP pages must exist in the App_GlobalResources of your IIS instance (each IIS instance on each farm machine) to be available to your ASP code. The real question is how do you get your resources there?  I am aware of four main solutions.

1)      The SPWebApplicationBuilder copies items in from the 12 hive directory 12\CONFIG\Resources to the App_GlobalResources at the time of web application creation.  You can place resources into this directory with global solution deployment (assuming SPSolution.ContainsWebApplicationResource = false for your SPSolution).  Now these resources will be available to all new web applications created.  This limits your solution to use on only new web applications.

2)      You can place your resources into the 12 hive directory 12\CONFIG\Resources during deployment of any solution and then call “stsadm -o copyappbincontent”.  It works great.  This has the side effect of updating the App_GlobalResources of all Web Applications on the farm from the 12 hive CONFIG directory.  Some in the SharePoint community suggest that this is like using a sledge hammer to drive a pin in place.  It may have negative impacts upon other web applications.

3)      You can create a SPJobDefinition that copies the ASP resources to the App_GlobalResources and provision the job definition from a SPFeatureReceiver or SPWebProvisioningProvider .  The scope of the feature should match the scope of the ASP code that the resources support. 

4)      The final option is to not use .resx references in your ASP pages.  Instead build properties on code behind objects with properties that then reference back to imbedded resource files.  In this solution you must deploy the resource DLL’s instead of dealing with the coping of .resx files to the App_GlobalResources directory.

I have seen examples of people using all of these approaches.

Monday, March 30, 2009

Activate-Once Hidden Farm Features

To create a dependent farm feature that is hidden and will activate only once, use a resource-hidden feature.  I explained Friday that hidden features automatically deactivate when the last feature dependent upon the hidden feature deactivates and that resource-hidden features do not.  So using a resource-hidden feature the feature does not deactivate.

The problem is that resource-hidden features do not automatically activate in the activation tree.  The solution for farm level features is to set the attribute ActivateOnDefault=”true” in the feature element API.  This will activate your farm level feature on deployment. Here is the feature.xml for the SPFeatureDefinition:

<?xml version="1.0" encoding="utf-8"?>
<Feature xmlns="http://schemas.microsoft.com/sharepoint/"
         Id="C595997F-F3DD-4677-82CF-02AF9FB73451"
         Title="$Resources:Resource_hidden_feature_DO_NOT_LOCALIZE"
         Description="$Resources:Resource_hidden_feature_DO_NOT_LOCALIZE"
         RequireResources="true"
         Hidden="false"
         Scope="Farm"
         ActivateOnDefault="true"
         ReceiverAssembly="My.Receiver.Assembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8d63fadacc3f6a0e"
         ReceiverClass="My.Receiver.RunOnceFarmFeatureReceiver">
</Feature>

In this example the code in the SPFeatureReceiver is run only once at initial SPSolution.Deploy.  The feature is resource-hidden so users cannot see it and will not deactivate it from the Central Administration UI.  The feature also will not be deactivated by any features which depend on this feature.   The feature will only be deactivated prior to uninstall.