- Overview of Features and Solutions
- Programming with Features
- Programming with Solutions
- Summary
Programming with Features
SharePoint includes a robust object model for working with Features that allows developers to enumerate installed and activated Features, to turn Features on and off, and to control the installation or removal of Features.
The object model for Features includes the following key classes:
- SPFeatureCollection/SPFeature—Refers to a Feature state at a given site hierarchy level. The presence of an SPFeature instance within a property of type SPFeatureCollection indicates that the Feature is active at that level.
- SPFeaturePropertyCollection/SPFeatureProperty—Represents a single property on a Feature or a collection of those properties.
- SPFeatureScope—Represents an enumeration of the possible scopes in which Features can be activated. Possible values are: Farm, WebApplication, Site, and Web.
- SPFeatureDefinition—Represents the basic definition of a Feature, including its name, scope, ID, and version. You can also store and retrieve properties of a Feature. Note that Feature properties apply globally to a single Feature definition, not to instances of Features activated throughout the farm.
- SPFeatureDependency—Represents a Feature upon which another Feature depends.
- SPElementDefinition—Represents a single element that will be provisioned when the Feature is activated.
Feature collections can be accessed from the following properties on their respective classes:
- Features on Microsoft.SharePoint.Administration.SPWebApplication
- Features on Microsoft.SharePoint.Administration.SPWebService
- FeatureDefinitions on Microsoft.SharePoint.Administration.SPFarm
- Features on Microsoft.SharePoint.SPSite
- Features on Microsoft.SharePoint.SPWeb
- ActivationDependencies on Microsoft.SharePoint.Administration.SPFeatureDefinition
The next few sections of this chapter provide many examples of programming with the Features portion of the SharePoint application programming interface (API).
Enumerating Features and Feature Definitions
It is important to recognize the difference between a Feature and a Feature definition. A Feature definition, as far as the object model is concerned, is an abstraction around the Feature manifest contained in a Feature directory in the Features directory. Feature definitions are installed at the farm (or server, if there is no farm) level.
A Feature is an instance of a Feature definition. Features can be activated or deactivated, and they exist at the various levels of scope such as the site or web level.
To enumerate the list of Feature definitions that are currently installed within a farm (which includes single-server farms and standalone servers, which are another form of single-server farms), you need to use an instance of the SPFarm class and access the FeatureDefinitions property. To enumerate the list of active Features on a given site, you need to enumerate the Features property on the appropriate SPWeb or SPSite class instance. You might be tempted to iterate through the collection contained in the Features property and look for something like an Active property. However, the only SPFeature instances that appear in the Features property are those features that are active in the current scope.
Creating an instance of the SPFarm class might seem a little tricky at first. Rather than obtaining it through a context provided by the Web Part manager or from a site uniform resource locator (URL), you need to pass a connection string that points to the farm's configuration database to the constructor. The connection string should look familiar to anyone with ADO.NET experience connecting to SQL server, because it is just a SQL server connection string.
The code in Listing 3.1 shows how to create an instance of the SPFarm class, create an instance of the SPSite class, and use the two of those to enumerate the list of installed Feature definitions and determine which of those definitions are active on the given site. This code is for a Windows Forms application that adds the name and enabled status of each Feature definition to a ListView control. If you plan to copy this code and test it, be sure to add a reference to the Microsoft.SharePoint.dll Assembly.
Listing 3.1 Enumerating Feature Definitions and Features
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using Microsoft.SharePoint; using Microsoft.SharePoint.Administration; using System.Windows.Forms; namespace FeatureEnumerator { public partial class Form1 : Form { private SPSite _rootCollection; public Form1() { InitializeComponent(); } private string GetFeatureEnabled(SPFeatureDefinition featureDefinition) { foreach (SPFeature feature in _rootCollection.Features) { if (feature.Definition.Id == featureDefinition.Id) return "Yes"; } return "No"; } private void button1_Click(object sender, EventArgs e) { featureList.Enabled = true; featureList.Items.Clear(); string dbConn = @"server=localhost\OfficeServers;initial catalog=SharePoint_Config_66140120-a9bf-4191-86b6-ec21810ca019;IntegratedSecurity=SSPI;"; _rootCollection = new SPSite(siteUrl.Text); SPFarm farm = SPFarm.Open(dbConn); statusLabel.Text = "Site Feature Status (" + farm.FeatureDefinitions.Count.ToString() + " Feature Definitions Installed)"; foreach (SPFeatureDefinition featureDefinition in farm.FeatureDefinitions) { ListViewItem lvi = new ListViewItem(featureDefinition.DisplayName); if (featureDefinition.Hidden) lvi.ForeColor = Color.Gray; lvi.Tag = featureDefinition.Id; lvi.SubItems.Add(GetFeatureEnabled(featureDefinition)); featureList.Items.Add(lvi); } } } }
This Windows Forms application is shown in Figure 3.1.
Figure 3.1 Feature Enumerator Windows Forms application.
The true power of Features should become immediately obvious as soon as you start using this tool to examine the list of active and inactive features on various sites. Most of the key functionality provided by SharePoint 2007 is implemented using Features. Previous versions of SharePoint did not provide anywhere near the amount of flexibility, customization, and enhancement capability that Features provide.
Activating and Deactivating Features
It follows that if the SPFeatureCollection instance represented by the Features property of a site or web object contains the list of active Features, then adding and removing to and from that collection should activate and deactivate Features. In fact, that is exactly how it works with one small exception: You cannot add or remove SPFeature or SPFeatureDefinition instances; you can only add or remove globally unique identifiers (GUIDs).
Before you start writing code that activates and deactivates Features, you should definitely create a test site that you don't mind destroying. Deactivating hidden features can have drastic consequences on the ability of your site to function properly. However, knowing what those consequences are can certainly provide deeper understanding of the Features system and time spent tinkering with Features is definitely time well spent.
To deactivate a Feature, simply remove it from the Features collection of the current site or web object:
currentSite.Features.Remove(new Guid("... guid of feature to remove ..."));
Conversely, activating an installed Feature on a site or web object is accomplished simply by adding the Feature's GUID to the Features collection:
currentSite.Features.Add(new Guid(".. guid .."));
Keep in mind that an exception will be thrown if you attempt to activate a Feature that cannot be activated at the current scope.
Using Feature Properties
Every Feature installed in SharePoint maintains its own property bag.
Features and Feature definitions both have properties exposed through the Properties property, which is of type SPFeaturePropertyCollection—a collection of SPFeatureProperty objects. Regardless of whether you access the Properties property of a site Feature instance or of a Feature definition, the result will be the same. That is, you can think of Feature properties as static, global data that belongs to the definition itself but can also be accessed from an activated Feature SPFeature object.
The following code snippet illustrates how to enumerate through the properties associated with a given Feature (or Feature definition):
foreach (SPFeatureProperty property in myFeature.Properties) { Console.WriteLine("{0} : {1}", property.Name, property.Value); }
You don't have to worry about typecasting or conversion because the only value type acceptable to a property bag is System.String. Adding a new property to an existing Feature or Feature definition is quite simple:
SPFeatureProperty prop = new SPFeatureProperty("myProp", "myValue"); myFeature.Properties.Add(prop);
That's all there is to it—you don't need to explicitly call any methods to commit that change to SharePoint. It is just as easy to remove a property from a Feature:
SPFeatureProperty prop = myFeature.Properties[0]; myFeature.Properties.Remove(prop);
A few of the Features that are installed with SharePoint make use of properties such as the workflow features. You can use properties to do tremendously powerful things. You can think of the property bag assigned to each Feature as either a place for global configuration settings or for global state management for the Feature, or both.
Installing and Removing Feature Definitions
To install a Feature definition, you need to make use of one of the overloads of the Add method on the SPFeatureDefinitionCollection class:
- Add(SPFeatureDefinition)—Adds a new Feature definition based on the properties of the SPFeatureDefinition instance passed to the method.
- Add(relative path to manifest, GUID of solution)—Adds a new Feature definition that resides in the location indicated by the first parameter with the given solution ID.
- Add(relative path to manifest, GUID of solution, force)—Adds a new Feature definition that resides in the location indicated by the first parameter with the given solution ID and forces a reinstallation of the Feature.
The following code is a simple example of installing a new Feature in a farm (remember that to get an instance of the SPFarm class, you need the connection string of the farm's configuration database):
SPFeatureDefinitionCollection installedFeatures = theFarm.FeatureDefinitions; installedFeatures.Add("newfeature", new Guid("- feature GUID -"));
Conversely, to uninstall a Feature, simply remove it from the collection. You can remove the Feature based on the relative path to the Feature manifest or the Feature's GUID:
installedFeatures.Remove(new Guid("- feature GUID -"));