FeatureReceiver To Cleanup WebPart Files

Many web-part developers are surprised to see that their web-parts are listed as available even though they have deactivated the feature which contains them

And the users are equally surprised when they then try to add the web-part only to see it fail because the code (and safe-control entry) has been removed.

The problem comes from the fact that deactivating a Feature doesn’t remove files provisioned using Module and File entries

The solution is quiet simple. Just make a feature receiver which deletes all the .webpart files in the FeatureDeactivating event. You can even get all the files to delete from the xml-files associated with the feature so the following code does it all automatically:

public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
    using (SPSite site = properties.Feature.Parent as SPSite)
    {
        RemoveWebParts(site, properties.Definition);
    }
}
 
private void RemoveWebParts(SPSite site, SPFeatureDefinition definition)
{
    using (SPWeb web = site.RootWeb)
    {
        string wpcatalogUrl = SPUrlUtility.CombineUrl(web.Url, "_catalogs/wp");
 
        // Get the Feature.xml for the feature
        //
        XmlDocument featureXml = new XmlDocument();
        featureXml.LoadXml(definition.GetXmlDefinition(web.Locale).OuterXml);
 
        XmlNamespaceManager nsMgr = new XmlNamespaceManager(featureXml.NameTable);
        nsMgr.AddNamespace("sp", "http://schemas.microsoft.com/sharepoint/");
 
        // Get the Location attribute of each ElementManifest inside each ElementManifests inside the Feature
        //
        foreach (XmlNode locationNode in featureXml.SelectNodes("/sp:Feature/sp:ElementManifests/sp:ElementManifest/@Location", nsMgr))
        {
            // Get the ElementManifest XML
            //
            XmlDocument elementManifest = new XmlDocument();
            elementManifest.Load(Path.Combine(definition.RootDirectory, locationNode.Value));
            XmlNamespaceManager nsMgr2 = new XmlNamespaceManager(elementManifest.NameTable);
            nsMgr2.AddNamespace("sp", "http://schemas.microsoft.com/sharepoint/");
 
            // Get the Url attribute of each file in Modules (with List attribute='113' WebPartCatalog
            //
            foreach (XmlNode webPartFileUrl in elementManifest.SelectNodes("/sp:Elements/sp:Module[@List='113']/sp:File/@Url", nsMgr2))
            {
                // Delete the file from the WebPart Catalog
                //
                SPFile wpFile = web.GetFile(SPUrlUtility.CombineUrl(wpcatalogUrl,webPartFileUrl.Value));
                wpFile.Delete();
            }
  
        }
    }
}

And if you combine this with the code from this post then you get a file like this which works even if the Feature is removed as part of a solution being retracted.

comments powered by Disqus