Showing posts with label SPFeature. Show all posts
Showing posts with label SPFeature. Show all posts

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.

Wednesday, November 4, 2009

PowerShell Setup for SharePoint 2010 Diagnostics

STSADM still ships with SharePoint 2010 but has been replaced with PowerShell as the preferred scripting engine for SharePoint. I rarely write SharePoint scripts, but I do often use these tools for testing. Lately I have been testing a lot of upgrade scenarios. To make the best use of PowerShell as a SharePoint diagnostic environment I have a few tips.

PowerShell Community Extensions – Get and install these extensions as they will make your PowerShell environment much nicer. Once installed, edit the (My)Documents\WindowsPowerShell\Profile.ps1 file to uncomment the Visual Studio environment variables. It is necessary to add ’10.0’ at the front of the comma separated list for “VisualStudioVersion”.

Auto Load the SharePoint Extension – Add the following line to your PowerShell profile.ps1 file to automatically load the SharePoint extension for PowerShell in every shell you launch.

& "C:\Program Files\Common Files\Microsoft Shared\Web Server xtensions\14\CONFIG\POWERSHELL\Registration\sharepoint.ps1"

PowerShell Threading Model and Extension Object Disposal – Each line entered in PowerShell is run by a single thread. This creates some problems because many SharePoint objects are attached to IIS COM objects and need disposal. The SharePoint extension methods for PowerShell deal with this to some extent. You get objects that appear to be the SharePoint .Net objects but are in some way disconnected from the IIS backend. The result is that some of the methods and properties of the object may not function. When you call these methods you may get a response that the object has been disposed.

Workaround for the Extension Object Disposal Problem - To get around this problem, use PowerShell to instantiate the .Net objects directly. This was possible with SharePoint 2007. When doing this, the object and the disposal should be contained in a single line of PowerShell (one thread). Here is an example of the threading model in practice:

PS> [Guid]$featureId="6d44695f-ca99-4c27-9b6b-2a39c62357a1"
PS>
$site=new-object Microsoft.SharePoint.SPSite("http://server/sitecollection"); site.RootWeb.Features[$featureId];$site.Dispose()

This example can be used to show the version of a particular feature. I have used this a lot while studying the new feature upgrade capabilities in SharePoint 2010. Upgrade is a subject for another time.

Finding the Right Cmdlet – Microsoft has yet to publish the PowerShell documentation for the SharePoint extension. It is possible to dig the list of Cmdlets from looking at the SharePoint API documentation. I find it easier to just play with them in PowerShell. I use the following help function to make it easier to find the Cmdlets I need. You can put this in your PowerShell profile.ps1 file to make it available.

function findhelp([string]$part)
{
help > c:\temp\helpjunk.txt
$lookingFor = ".*" + $part + ".*"
cat c:\temp\helpjunk.txt where {$_ -match $lookingFor}
}

Monday, April 20, 2009

Programmatically Activating Features just after Deployment

There are a variety of scenarios where features need to be programmatically activated just after a solution has been deployed.  I have found that even when the SPSolution object says it has been deployed, it really isn’t finished deploying.  Sometimes my SPFeatureDefinitions are either non existents or not installed even when the deployment is “done”.  They eventually do show up. Until they do, feature activation fails when the feature is added to the SPFeatureCollection of the SPFarm, SPWebApplication, SPSite, or SPWeb.  I ended up coding a small bit of code to work around this problem.  This example shows activation of a web application scope feature, but the algorithm can be applied to a feature of any scope.

private void ActivateWebApplicationFeature(Uri webApplicaitonUri, Guid featureId, int timeoutSeconds)
{
    const int sleepTime = 1000;
    for (int i = 0; i < timeoutSeconds; i++)
    {
        try
        {
            SPFeatureDefinition definition = SPFarm.Local.FeatureDefinitions[featureId];
            if (definition.Status == SPObjectStatus.Online)
            {
                break;
            }
            Thread.Sleep(sleepTime);
        }
        catch
        {
            Thread.Sleep(sleepTime);
        }
    }
    SPWebApplication application = SPWebApplication.Lookup(webApplicaitonUri);
    if (application.Features[featureId] == null)
    {
        AddWebApplicationFeature(webApplicaitonUri, featureId);
    }
}

private void AddWebApplicationFeature(string webApplicaitonUri, Guid featureId)
{
    int count = 0;
    while (true)
    {
        try
        {
            SPWebApplication application = SPWebApplication.Lookup(webApplicaitonUri);
            application.Features.Add(featureId);
            application.Update();
            break;
        }
        catch (SPDeletedConcurrencyException)
        {
            // Done. This object is gone so we are finished.
            // Optional logging of condition
            break;
        }
        catch (SPUpdatedConcurrencyException)
        {
            count++;
            if (count > 10)
            {
                throw;
            }
        }
    }
}

The algorithm is to first wait for the feature definition to appear.   When looking up the SPFeatureDefinition in the SPFeatureDefinitionCollection an exception will be thrown until the definition has been added.  The code waits a second between checks.  It continues waiting for the SPFeatureDefinition to install.  Finally it activates the feature if the feature needs activation (in certain upgrade scenarios the feature may already be active).  You will notice that the second method uses my technique to control SPDeletedConcurrencyException and SPUpdatedConcurrencyException

Wednesday, April 15, 2009

Best Practices for SharePoint Solutions

Here are my personal requirements that I use for applications built on SharePoint.  I think they embody many of the best practices.

Applications should be SharePoint Solutions

·         Each application should be self contained in a single SharePoint solution .wsp file.

o   Including all DLL’s to GAC

o   Including all SafeControls

o   Including all Templates

o   Including all Features

o   Including all List and Item Schema

·         Including all WebServices  and HttpHandlers for data communication

·         Solutions should be deployable (SharePoint’s concept of an internal install) to a new Web Application or one or more existing Web Applications.

·         Solutions should not be global to the farm (SharePoint has the concept of a global solution deployment) as this prevents multiple versions of the same solution from coexisting on the farm.

·         Solutions must be visible in the Farm Solution Manager so they may be retracted from the SharePoint farm.

·         Solutions should properly clean up themselves upon a Solution retraction.

·         Solutions must play friendly with third party applications

o   Unique ID’s on all objects

o   Unique namespace within file store

o   Never override or modify built in items

o   Smart about web application configuration

·         Solution version to version compatibility must be maintained

o   If the site template needs to be upgraded

§  Never change ID or site template (no delete)

§  Add a new site template into the system with the new functionality

§  Preserve all old template definitions

·         there may be existing site content built on this template

·         there may be customer customized site templates built on this template

·         PTC partners may have built their own templates on top of existing templates

§   Mark old template definitions as hidden so that customers are discouraged from using old site definitions

§  Feature staple new features to old site definitions to add new features to previously installed sites

o   If a list definition needs to be upgraded

§  Never change ID or  remove a list definition (no delete)

·         Never remove a content type

§  add a new list definition into the system with the new functionality

§  Preserve all old list definitions

·         They may have been customized and migration is impossible without loss of customization

§  Mark old list definitions as hidden so that customers are discouraged from using old list definitions

§  Repurpose the Microsoft’s SharePoint Upgrade Schema system to upgrade old lists to new lists

o   If a feature definition needs to be upgraded

§  Never change ID or remove a feature definition (no delete)

§  Do not remove any existing element definitions

o   If a administrative object needs to be upgraded

§  Should maintain deserialization between versions

§  Override the Upgrade method in the SPPersistedObject to perform self upgrade

§  Detect old status (when deserialized) and implement the NeedsUpgrade property

§  Maintain all API’s from version to version (no delete on API)

 

Thursday, April 2, 2009

Uniquely Name Features

For SharePoint Features deployed into the 12 hive at the root of the feature directory it is necessary to remember that the name of your feature must be unique. The 12 hive feature (12\Templates\Features) directory is a global namespace and your feature directory should not trample another third party feature. I recently had to explain this to a developer who was provisioning “SearchWebPart” a feature with a very generic name.

My recommendation is to use the following naming convention for your feature directory: CompanyApplicaitonFeaturename. By doing this you will avoid colliding with other features deployed by other solutions running in the SharePoint farm.

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.

Thursday, March 26, 2009

Resource-Hidden Features can have ActivationDependencies

What is a resource-hidden feature?  It is a feature that is hidden from the user using a loophole in the SPFeatureDefinition API that is intended to show locale specific features.

Basically the feature element API says that the attribute RequireResources=”true” will prevent a feature from appearing in the GUI feature list if a resource file for the locale cannot be found.  A resource-hidden feature exploits this by providing no resources for any locales. Here is what the feature.xml looks like:

<?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="Site">
  <ActivationDependencies>
    <ActivationDependency FeatureId="0D7EE02B-F92F-4ed2-97F7-349AEC1E0517" />
    <ActivationDependency FeatureId="5730DE72-D669-4fc7-9EA1-BC50826EF575" />
    <ActivationDependency FeatureId="C3BAA93D-B3DE-424c-850A-E19253068473" />
  </ActivationDependencies>
</Feature>

You might ask why would you use a resource-hidden feature instead of a regular hidden feature with the attribute Hidden=”true”?  Simply because the two have different behaviors:

·         Activation – Hidden features auto-activate in the feature dependency chain. Resource-hidden features do not.

·         Deactivation – Hidden features which are dependent features, deactivate when the last feature depending upon them deactivates. Resource-hidden features do not.

·         Dependency  Tree – Hidden features cannot have any ActivationDependencies. Resource-hidden features can.

Remember resource-hidden features cannot be seen in the UI and do not auto-activate so they must be programmatically activated by adding them to a SPFeatureCollection.