Features inside a Solution isn't deactivated when the Solution is retracted

Features and Solutions are two of the best features in WSS 3.0 (except for their names, which makes it very hard to write and speak about them):

One of the great strengths of Features is the ability to have code executed when the Feature is activated and again when it’s deactivated. This is very handy for doing any kind of setup and teardown. Especially as there is quiet a few of the declarative features of Features which only works on the first activation (e.g. existing files/content types isn’t updated) and some of the declarative features which is left when deactivating. In the last category is the one that surprises web-part developers most. They’ve learnt to install .webpart files into the WebPart gallery using Module/File elements and are quiet surprised when they later deactivate their feature and finds that the WebParts is still listed as being available because the .webpart files are left in the WebPart gallery, but when users then try to add the webpart it fails because the code has been removed. See this post on how to fix that.

The possibility to execute code on install/uninstall of a feature isn’t normally that interesting until you notice the bug in the Feature/Solution cooperation. Features inside a Solution isn’t deactivated when the Solution is retracted. Instead the solution just uninstalls the feature while it’s still activated, this means that the e.g web parts is removed but that the FeatureDeactivating code isn’t run with all kinds of nasty error as a result.

The following code is a HACK which fixes this bug and deactivates the Feature if it’s still activated when it’s uninstalled.

public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
{
    // HACK:
    // As solution retraction just uninstalls features without first deactivating
    // them, the code associated with FeatureDeactivating isn't executed unless
    // we deactivate the features ourselves
    // This code runs through all site and deactivates the feature on uninstall
    //
    foreach (SPWebService webService in new SPWebServiceCollection(SPFarm.Local))
    {
        foreach (SPWebApplication webApp in webService.WebApplications)
        {
            foreach (SPSite site in webApp.Sites)
            {
                try
                {
                    foreach (SPFeature feature in site.Features)
                    {
                        if (feature.DefinitionId == properties.Definition.Id)
                        {
                            site.Features.Remove(properties.Definition.Id);
                            break;
                        }
                    }
                }
                finally
                {
                    site.Dispose();
                }
            }
        }
    }
}
comments powered by Disqus