FeatureReceiver To Cleanup WebPart Files
14-Jul-2008SharePoint 2007
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.