The SPFeatureReceiver is a handy tool for capturing the activation and deactivation of a SharePoint feature. In this article we will take a look at what is required to remove the WebPart from the WebPart catalogue when deactivating a feature in SharePoint. When removing a WSP package or a feature the WebParts are left behind in the catalogue, creating orphaned entries that can quickly grow, and can cause some major issues when developing and redeploying.

Some assumptions are made with this article and are outlined here for easy reference:

  • The WebPart is called MySharePoint.MyWebPart.
  • The WSP package is already created.
  • The WSP was created using the SharePoint Development Environment described here.

However the code and principles will apply in your development environment and style of choice, the above is just to clarify where and how this was tested. There is a few steps involved in making the Feature Receiver do it’s job, and there is also some important items to take note of:

  • There only needs to be one SPFeatureReceiver per WSP. (Multiple SPFeatureReceiver generate compile time GUID errors)
  • The events are only fired when using stsadm to deploy the WSP file or deploy feature in Visual Studio.

Step 1: Inherit and Implements SPFeatureReceiver

The first step in creating the Feature Receiver is to create a new class which inherits the SPFeatureReceiver class. This requires a reference to the Microsoft.SharePoint assembly.

   1: namespace MySharePoint
   2: {
   3:     using System;
   4:     using System.Security.Permissions;
   5:     using Microsoft.SharePoint;
   6:     using Microsoft.SharePoint.Security;
   7:  
   8:     public class FeatureRecieverSample : SPFeatureReceiver
   9:     {
  10:         public override void FeatureActivated(SPFeatureReceiverProperties properties)
  11:         {
  12:         }
  13:  
  14:         public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
  15:         {
  16:         }
  17:  
  18:         public override void FeatureInstalled(SPFeatureReceiverProperties properties)
  19:         {
  20:         }
  21:  
  22:         public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
  23:         {
  24:         }
  25:     }
  26: }

 

A detailed explanation of the SPFeatureReceiver can found on MSDN here.

Step 2: Link the Receiver to your WebPart

To link the receiver to your WebPart your assembly should be signed and you need to know the exact assembly information as reported in the global assembly cache. The receiver is called by stsadm and passed the relevant information it requires in the properties variable. The link to the receiver is done as part of the feature.xml file generated for the WSP file. The receiver is registered using the ReceiverAssembly and ReceiverClass properties. The feature.xml file can be found in the WSP view in Visual Studio.

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <Feature Id="de9e1722-a1ec-41cc-8762-1921ad877451" 
   3:          Title="MyWebPart" 
   4:          Scope="Site" 
   5:          Version="1.0.0.0" 
   6:          Hidden="FALSE" 
   7:          DefaultResourceFile="core" 
   8:          xmlns="http://schemas.microsoft.com/sharepoint/"
   9:          ReceiverAssembly="MySharePoint.MyWebPart, Version=1.0.0.0, Culture=neutral, 
  10:                                 PublicKeyToken=5aa40f345eed13a4"
  11:          ReceiverClass="MySharePoint.FeatureReceiverSample">
  12:   <ElementManifests>
  13:     <ElementManifest Location="MyWebPart.xml" />
  14:     <ElementFile Location="MyWebPart.webpart" />
  15:   </ElementManifests>
  16: </Feature>

Step 3: Find the WebPart to remove and delete it from the catalogue.

To remove the WebPart currently being deactivated the properties need to be interrogated. There is various ways to find the WebPart, however using the full assembly name is the best possible option to avoid deleting WebParts with the same name. In this sample Linq to Xml is used to retrieve the namespace from the Xml however XPath or an XmlReader can also be used. Reflection can be used to determine the namespace but for simplicity it has been hardcoded in the sample below.

   1: public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
   2: {
   3:     SPSite selectedSite = null;
   4:     if (properties.Feature.Parent is SPSite)
   5:     {
   6:         selectedSite = (SPSite)properties.Feature.Parent;
   7:     }
   8:  
   9:     SPListItem listDeleteItem = null;
  10:     Type checkWebPart = Type.GetType(String.Format(CultureInfo.InvariantCulture, "{0}.{1}", 
  11:                                                     "MySharePoint", properties.Definition.DisplayName));
  12:     if (selectedSite != null)
  13:     {
  14:         SPWeb selectedWeb = selectedSite.RootWeb;
  15:         SPList selectedList = selectedWeb.GetCatalog(SPListTemplateType.WebPartCatalog);
  16:         if (selectedList.ItemCount > 0)
  17:         {
  18:             foreach (SPListItem selectedListItem in selectedList.Items)
  19:             {
  20:                 StringReader itemXmlRaw = new StringReader(selectedListItem.Xml);
  21:                 XDocument itemXml = XDocument.Load(itemXmlRaw);
  22:                 XName itemXmlAttribute = XName.Get("ows_WebPartTypeName");
  23:                 string itemType = itemXml.Root.Attribute(itemXmlAttribute).Value;
  24:                 if (itemType == checkWebPart.FullName)
  25:                 {
  26:                     listDeleteItem = selectedListItem;
  27:                     break;
  28:                 }
  29:             }
  30:  
  31:             if (listDeleteItem != null)
  32:             {
  33:                 selectedList.Items.DeleteItemById(listDeleteItem.ID);
  34:             }
  35:         }
  36:     }
  37: }

 

Conclusion

Once implemented the feature receiver can be wired to multiple WebParts in the same project to neatly deactivate and remove the orphaned WebPart entries from the WebPart catalogue. The process allows for easy maintenance of multiple WebParts and keeps the catalogue clean and easy to navigate, and also stops users from loading WebParts that has been deleted already. It also demonstrates to use of some Framework 3.5 features in SharePoint.