Getting Sites and Webs during Feature Activation in SharePoint

One of the cool features in SharePoint 2007 are Feature Event Classes. These classes allow you to trap and respond to an event that fires when a feature is installed, activated, deactived, or removed. While you can't cancel an installation or activation through the events, you can use them to your advantage to manipulate the scoped item they're operating on.

In my SharePoint Forums Web Part, I had delegated the creation of the lists to the web part itself whenever it was added to a site. Of course I didn't go farther and clean up the lists the web part created when it was removed because there was no way to tell when someone removed a web part from a page (since it might not be the only one on the page). This has led to various problems (users had to be server admins to make this work 100% of the time, lists left over from old installs) but in the 2007 version Feature Event Recievers come to the rescue. Now when you activate the Forums on a web, it creates the needed lists and when you deactivate it the receiver removes them. You create a Feature Reciever by inheriting from the base class of SPFeatureReceiver. In it there are 4 methods you can override (activating, deactivating, installing, uninstalling).

One thing you don't have is a Context object so it makes it a little tricky to get the SPSite/SPWeb object the feature is activating on. Luckily there's a nice property (of type object) in the SPFeatureReceiverProperites object that gets passed to each method. This class contains a property class Feature which in turn contains a property called Parent. The Parent property is the scoped item that is working against the feature so if you scope your feature to Web, you'll get a SPWeb object (Site for an SPSite object, etc.). This is the key in getting a hold of and manipulating your farm/server/site/web when a feature is accessed.

Here's an example of a feature. When the feature is activated, it creates a new list. When it's deactivated it removes the list.

public class FeatureReceiver : SPFeatureReceiver
{
    public override void FeatureActivated(SPFeatureReceiverProperties properties)
    {
        using (SPWeb web = (SPWeb) properties.Feature.Parent)
        {
            web.Lists.Add("test", "test", SPListTemplateType.GenericList);
        }
    }
 
    public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
    {
        using (SPWeb web = (SPWeb) properties.Feature.Parent)
        {
            SPList list = web.Lists["test"];
            web.Lists.Delete(list.ID);
        }
    }
 
    public override void FeatureInstalled(SPFeatureReceiverProperties properties)
    {
        /* no op */
    }
 
    public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
    {
        /* no op */
    }
}

BTW, it's not clear to me if getting an SPWeb object through this means requires the disposing of it. See Scott Harris and Mike Ammerlaans excellent must-read article here on scoped items which might help. For me, this is the safest approch (the object will always fall out of scope and dispose of itself). It might be overkill but it works. Feature receivers are not the easiest things to debug.

Enjoy!

6 Comments

  • Hi Bill, As a rule of thumb you'll want to dispose any SPSite and SPWeb object you create. Any that are apart of the current context, you must leave alone or you'll cause an error by disposing them. In the example above, you're getting a new instance of SPWeb, making it completely appropriate to dispose it.

  • Did you figure out how to debug FeatureEventReceiver? Im hanging on the same thing .. Each commands when installing is a separate one to stsadm.exe. You dont realy have a chance to attach to anything with VS2008. The only option that comes to my mind is writing info to log (very uncomfortable).

  • @Leon: The using statement around the SPWeb object above will clean up when it falls out of scope.

  • @melborp: I don't know if there's a way to debug it properly. One thing you might try (don't know if this works or not) is to set a breakpoint in your code and set your debugger to stsadm.exe. Logging is really the only uncomfortable way to do it off the top of my head but not very pretty.

  • @melborp: Thanks for the link! Works like a charm.

  • The best way to debug a feature at the moment of installing it is to hook unto STSADM itself.

    1- Make a Thread.Sleep long enough for you to hook onto it (inconvenient)
    2- Go in Project Properties (the one that contain your dll) and set the starting program to STSADM and the command line arguments to what you want to call your custom command. Then all you have to do is "F5". Very convenient.

Comments have been disabled for this content.