Generic Feature Receiver for Features that Deploy WebParts

Greg Galipeau wrote a thorough post on cleaning up your Web Part Gallery that is the basis for this post. To summarize, Greg shares a Feature Receiver he uses as a generic Feature Receiver for all his WebPart Features that simply removes the WebPart having the same name as the Feature’s DisplayName when the Feature is deactivated.

There are a couple of issues with this though:

  1. It assumes that the WebPart has the same name as the Feature
  2. It limits the Feature to deploying just a single WebPart

An alternative approach would be to inspect the Feature’s element definitions and extract the exact WebPart names that were deployed, thus resolving the two issues noted above.

Below is the alternative Feature Receiver (it extends the BaseFeatureReceiver I mentioned in my previous post):

    public class WebPartFeatureReceiver : BaseFeatureReceiver<SPSite>
    {
        public override void FeatureDeactivating(SPSite site, SPFeatureReceiverProperties properties)
        {
            base.FeatureDeactivating(site, properties);
 
            var elements = properties.Definition.GetElementDefinitions(CultureInfo.CurrentCulture);
            var webparts = elements.Cast<SPElementDefinition>()
                .SelectMany(e => e.XmlDefinition.ChildNodes.Cast<XmlElement>()
                    .Where(n => n.Name.Equals("File"))
                    .Select(n => n.Attributes["Url"].Value)
                    )
                .ToList();
 
            var rootWeb = site.RootWeb;
            var wpGallery = rootWeb.Lists["Web Part Gallery"];
 
            var galleryItems = wpGallery.Items.Cast<SPListItem>()
                .Where(li => webparts.Contains(li.File.Name))
                .ToList();
 
            for (int i = galleryItems.Count - 1; i >= 0; i--)
            {
                var item = galleryItems[i];
                item.Delete();
            }
        }
    }

5 Responses to “Generic Feature Receiver for Features that Deploy WebParts”

  • John Powell Says:

    Nice work!

  • Perry Says:

    What namespaces are required?

    I can’t figure out what namespace is required to solve the error:

    Error 1 ‘Microsoft.SharePoint.Administration.SPElementDefinitionCollection’ does not contain a definition for ‘Cast’ and no extension method ‘Cast’ accepting a first argument of type ‘Microsoft.SharePoint.Administration.SPElementDefinitionCollection’ could be found (are you missing a using directive or an assembly reference?)

  • Trent Says:

    @Perry – Thanks for bringing this up. The ‘Cast’ method is an extension method located in the System.Linq.Enumerable class. You will need to include a using statement for the System.Linq namespace. Extension methods can be a little tricky to track down.

  • Jan Says:

    Hi,

    if you change
    var wpGallery = rootWeb.Lists["Web Part Gallery"];
    into
    var wpGallery = rootWeb.GetList(“/_catalogs/wp”);

    It will work in other languages

  • DenisR Says:

    Thanks for the solution.

    I would recommend more unified way of loading web parts gallery (without string hardcoding):
    var webPartsGallery = rootWeb.GetCatalog(SPListTemplateType.WebPartCatalog);

    It works without problems for me.

Leave a Reply