Logo
CAR REVIEW
Windows Vista
Windows 7
Windows Azure
Windows Server
Windows Phone
PREGNANCY
 
 
Windows Server

SharePoint 2010 : Packaging and Deployment Model - Features (part 2) - Feature Receivers

1/7/2013 3:41:52 PM

2. Feature Receivers

A feature receiver is basically an event handler responsible for handling installation and activation events for a feature. We can add feature receivers to any type of feature by right-clicking a Feature node in the Solution Explorer pane and selecting Add Event Receiver. When we perform this action, Visual Studio adds a new code file to our project and sets the Receiver Assembly and Receiver Class properties of the feature to reference the new code file. Let’s do this now:

  1. Right-click the Features node and select Add Feature. A new feature named Example 19 Feature 2 will be added to the project.

  2. Right-click the Feature2 node in the Features folder and select Add Event Receiver.

  3. Double-click Feature2.feature in the Feature 2 folder. In the Properties pane, the Receiver Assembly and Receiver Class have been automatically set.

In the Feature2.EventReceiver.cs file are five commented methods representing the events that can be handled by the feature receiver. By uncommenting these methods, we can add custom code to do whatever we need to do. As you embark on more complex SharePoint projects, you’ll find that although you can perform much configuration using the SharePoint Project Items available in Visual Studio, a lot of configuration still needs to be done programmatically. In these situations, the feature receiver is the tool of choice. Bearing that in mind, let’s look at how feature receivers work and how we can best make use of them.

  1. Add the following code to Feature2.EventReceiver.cs:

       public override void FeatureActivated(SPFeatureReceiverProperties properties)
       {
         if (properties.Feature.Parent is SPWeb)
         {
           SPWeb web = properties.Feature.Parent as SPWeb;
    
           Guid listId=web.Lists.Add("My New List",
                                   "This is a demonstration list",
                                   SPListTemplateType.Contacts);
           SPList newList = web.Lists[listId];
           newList.OnQuickLaunch = true;
           newList.Update();
        }
      }
    
      public override void FeatureDeactivating(
                                SPFeatureReceiverProperties properties)
     {
    
       if (properties.Feature.Parent is SPWeb)
       {
         SPWeb web = properties.Feature.Parent as SPWeb;
    
         SPList myList = web.Lists.TryGetList("My New List");
    
         if (myList != null)
         {
            myList.Delete();
         }
       }
    }
    
    
    					  
  2. Deploy the solution by selecting Deploy Example 19 from the Build menu.

If all is well, we’ll find that our blank demo site now contains two new lists: one named Example - ListInstance1, which has been created by the ElementManifest in Feature1, and another named My New List, which has been created programmatically by our feature receiver in Feature 2.

Notice in this code snippet that we’re using the properties.Feature.Parent property to obtain a reference to the SPWeb object on which our feature is being installed. Some investigation of the Parent property will reveal that it’s of type object, and for that reason we’re checking its type before casting it to a variable of the correct type. To understand why this is the case, you can take a look at how features are defined within the server object model, as shown here:

Features can have four possible scopes. When a feature of a particular scope is installed, it’s added to the Features collection of the appropriate object. For example, a site collection–scoped feature would be added to the Features collection of the appropriate SPSite object. The SPFeature object that is returned by properties.Feature can therefore have one of four possible parents, depending on the scope of the feature.

To confirm that our receiver is working as expected, we can take the following steps:

  1. From the Site Actions menu, select Site Settings, and then select Manage Site Features from the Site Actions section.

  2. Both Example 19 Feature 1 and Example 19 Feature 2 are active. Deactivate Example 19 Feature 2. Notice that My New List is removed from the site. This confirms that our feature receiver is working as expected.

Debugging Feature Receivers

Feature receivers can be difficult to debug because they are often executed within a separate process. To see an example of this problem, put a breakpoint on the first line of our FeatureActivated method and try debugging using Visual Studio. The code will be deployed and the feature will be activated, but execution will not stop at the breakpoint. Visual Studio makes use of a separate process, VSSPHost4.exe, to automate the deployment process. The Visual Studio debugger, however, is set up to attach to a W3SVC.exe process only, and therefore the breakpoint is never hit but the code still executes.

We can work around this issue in one of two ways: we can either attach a debugger to the appropriate process, or we can ensure that our feature receiver runs in the W3SVC process. To ensure that a debugger is attached to the correct process, we can take the following steps:

  1. Add the following line of code to the method to be debugged:

          Debugger.Break();
    
  2. Start the debugging process as normal. An error dialog will be displayed:

  3. Click Debug The Program, and then in the Visual Studio Just-In-Time Debugger select the appropriate instance of Visual Studio. Click Yes to begin debugging.

This technique will work regardless of the host process. For example, if PowerShell is used to install a package, the same error dialog will be displayed.

Our second option is to ensure that the feature receiver code runs in the W3SVC process. This is relatively easy to do. Earlier when we looked at feature properties, we saw that the Activate On Default value is used to determine whether a feature should be automatically installed. We can use this setting as follows:

  1. Remove the line of code that we added in the preceding example.

  2. Double-click the Feature 2 node and set the Activate On Default property to False.

  3. Debug the solution as normal. This time, when the solution is deployed, our feature will not be automatically activated.

  4. When the web site being debugged is shown in the browser, select Site Settings from the Site Actions menu, and then select Manage Site Features from the Site Actions section. Manually activate the feature being debugged. The debugger will now stop on the breakpoints.

This method works because when features are activated via the user interface, the feature receiver runs under the W3SVC process, and Visual Studio has attached a debugger to this process as part of the standard debugging mechanism.

Passing Parameters to Feature Receivers

You’ve seen how to create feature receivers and how to pick up references to the object that you need in order to access the server object model. We’ve looked at a few ways to enable debugging. Let’s move on to look at more complex feature receivers.

As mentioned, practically every real-world SharePoint project will require some custom feature receivers. This is especially true when code being developed must be shared among multiple developers or deployed to testing or staging environments. As a result, it is sensible to create a library of feature receivers that perform specific configuration tasks. For example, I have a collection of feature receivers that perform actions such as configuring security for a site or setting up search scopes. These are actions that are common to many SharePoint projects but that can’t be performed declaratively.

One essential aspect of creating reusable feature receivers is the ability to pass configuration into the receiver. Let’s look at a few ways to solve this problem.

The first method is appropriate if a collection of name/value pairs is sufficient for our purposes.

  1. Open the Feature Designer for Feature 2.

  2. Add the FirstElement element that we created earlier to the feature, as shown:

  3. In the Solution Explorer pane, select the First Element node. Then in the Properties pane, click the ellipsis next to Feature Properties.

  4. Add two new properties, ListName and ListDescription. Set the values to Another New List and This is Another list, respectively.

  5. Click OK to close the dialog.

    Although every element in a feature has a Feature Properties property, in reality the properties are applied at the feature manifest level—that is, the combination of all the properties that are added to each element in Visual Studio are actually written within a single Properties element in the feature manifest.

  6. Update the code in Feature2.EventReceiver.cs as follows:

    public override void FeatureActivated(SPFeatureReceiverProperties properties)
      {
        if (properties.Feature.Parent is SPWeb)
        {
          SPWeb web = properties.Feature.Parent as SPWeb;
          string listName = properties.Definition.Properties["ListName"].Value;
          string listDescription = properties.Definition.Properties["ListDescription"].Value;
          Guid listId = web.Lists.Add(listName,
                                      listDescription,
                                      SPListTemplateType.Contacts);
          SPList newList = web.Lists[listId];
          newList.OnQuickLaunch = true;
          newList.Update();
        }
      }
    
      public override void FeatureDeactivating(
                                  SPFeatureReceiverProperties properties)
      {
        if (properties.Feature.Parent is SPWeb)
        {
         SPWeb web = properties.Feature.Parent as SPWeb;
         string listName = properties.Definition.Properties["ListName"].Value;
         SPList myList = web.Lists.TryGetList(listName);
         if (myList != null)
       {
         myList.Delete();
       }
      }
    }
    
    
    					  

You can see that we’re able to address the properties via the properties.Definition object. The Definition object is of type SPFeatureDefinition and is an object representation of the various XML elements that make up the feature.

The next method for solving the problem is appropriate if more complex configuration is required. For example, when configuring security settings for a site using a feature receiver, I use this approach to load an XML file containing the security configuration (see http://spsecurity.codeplex.com/ for more details).

  1. Add an XML file named MyConfig.xml to the FirstElement folder. Add the following code:

         <Lists>
          <List name="1st List" description="1st list description"
                type="Contacts"/>
          <List name="2nd List" description="2nd list description"
                type="Announcements"/>
          <List name="3rd List" description="3rd list description"
                type="Events"/>
         </Lists>
    
  2. To specify that the MyConfig.xml should be included as an element file, select the MyConfig.xml node in the Solution Explorer. Then, in the Properties pane, change the Deployment Type to ElementFile, as shown here:

  3. Update the code in Feature2.EventReceiver.cs as follows:

    public override void FeatureActivated(
                                SPFeatureReceiverProperties properties)
        {
          if (properties.Feature.Parent is SPWeb)
          {
            SPWeb web = properties.Feature.Parent as SPWeb;
            using (Stream s = properties.Definition.GetFile(
                                               "FirstElement\\MyConfig.xml"))
            {
              using (XmlReader rdr = XmlReader.Create(s))
              {
                rdr.ReadToDescendant("List");
                do
                {
                  string listName = rdr.GetAttribute("name").ToString();
                  string listDescription = rdr.GetAttribute(
                                                    "description").ToString();
                  string listType = rdr.GetAttribute("type").ToString();
                  SPListTemplateType typeEnum = (SPListTemplateType)Enum.Parse(
                                         typeof(SPListTemplateType), listType);
                  Guid listId = web.Lists.Add(listName,
                                              listDescription, typeEnum);
                  SPList newList = web.Lists[listId];
                  newList.OnQuickLaunch = true;
                  newList.Update();
                } while (rdr.ReadToNextSibling("List"));
              }
            }
          }
        }
    
         public override void FeatureDeactivating(
                                         SPFeatureReceiverProperties properties)
         {
           if (properties.Feature.Parent is SPWeb)
           {
             SPWeb web = properties.Feature.Parent as SPWeb;
             using (Stream s = properties.Definition.GetFile(
                                                  "FirstElement\\MyConfig.xml"))
             {
               using (XmlReader rdr = XmlReader.Create(s))
               {
                 rdr.ReadToDescendant("List");
                 do
                 {
                   string listName = rdr.GetAttribute("name").ToString();
                   SPList myList = web.Lists.TryGetList(listName);
                   if (myList != null)
                   {
                     myList.Delete();
                   }
                 } while (rdr.ReadToNextSibling("List"));
               }
             }
           }
         }
    
    
    
    					  

When we deploy the solution and activate the feature, three new lists will be added to the site as specified in the MyConfig.xml file. In this example, we’ve used an XmlReader to parse the configuration file for the sake of keeping the example simple. In a real-world solution, using an XmlSerializer to deserialize the configuration file into an appropriate collection of objects would be more robust.

Other -----------------
- SharePoint 2010 : Packaging and Deployment Model - Working with Packages
- Microsoft Content Management Server Development : Validating the HtmlPlaceholderControl (part 3) - Building the Required HTML Placeholder Validator
- Microsoft Content Management Server Development : Validating the HtmlPlaceholderControl (part 2) - Checking for an Empty HtmlPlaceholderControl
- Microsoft Content Management Server Development : Validating the HtmlPlaceholderControl (part 1) - Retrieving the Current Value of the HtmlPlaceholderControl
- Windows Server 2003 on HP ProLiant Servers : Migration Case Studies (part 3) - Hewlett-Packard Company
- Windows Server 2003 on HP ProLiant Servers : Migration Case Studies (part 2) - Eastman Chemical Company
- Windows Server 2003 on HP ProLiant Servers : Migration Case Studies (part 1) - County Government Office
- System Center Configuration Manager 2007 : Network Design - Troubleshooting Configuration Manager Network Issues (part 2) - Identifying Network Issues Affecting Configuration Manager
- System Center Configuration Manager 2007 : Network Design - Troubleshooting Configuration Manager Network Issues (part 1)
- System Center Configuration Manager 2007 : Network Design - Network Discovery
- Exchange Server 2007 : Deploying a Cluster Continuous Replication Mailbox Cluster (part 2)
- Exchange Server 2007 : Deploying a Cluster Continuous Replication Mailbox Cluster (part 1)
- Microsoft Dynamic AX 2009 : Report Customization (part 2) - Adding Promotional Materials to an Invoice Report
- Microsoft Dynamic AX 2009 : Report Customization (part 1) - Creating Promotional Materials
- Leveraging the SharePoint Workspace : Edit a List Item Using the Edit Form Offline, Create a New List Item Using the New Form Offline, Synchronize Offline Changes to SharePoint
- Leveraging the SharePoint Workspace : Leveraging the SharePoint Workspace, View Your List and Display Form Offline
- BizTalk Server 2009 Operations : Disaster Recovery (part 2)
- BizTalk Server 2009 Operations : Disaster Recovery (part 1) - Configuring the Destination System for Log Shipping
- Windows Server 2008 : Promoting a Domain Controller with dcpromo
- Windows Server 2008 : Retrieving Information About Objects with dsget, Viewing and Modifying AD Permissions with dsacls
 
 
Most view of day
- Windows Server 2012 Administration : Configuring Sites (part 1) - Creating a Site - Creating Site Subnets
- Creating a Home Network : Setting Up a Wired Network with an ICS Host
- Windows Server 2008 Server Core : Outputting Data Files with the Type Command
- Windows Phone 8 : Configuring Basic Device Settings - Date and Time (part 1) - Setting the Date and Time
- Editing Digital Video with Windows Live Movie Maker (part 9) - Sharing Your Videos - Outputting to the PC
- Sharepoint 2013 : Backup and Restore (part 1) - Site Collection Backups
- Games and Windows 7 : Using the Games Explorer (part 4) - Managing Your Game Controllers and Other Game-Related Hardware
- Microsoft Visio 2010 : Finding and Managing Shapes (part 2) - Searching for Shapes
- SQL Server 2008 R2 : Configuring Resource Governor (part 1) - Enabling Resource Governor, Defining Resource Pools
- How to Troubleshoot Disk Problems (part 1) - How to Prepare for Disk Failures, How to Use Chkdsk
Top 10
- Windows Phone 8 : Scheduled Tasks - Scheduled Task API Limitations
- Windows Phone 8 : Scheduled Tasks - Updating Tiles Using a Scheduled Task Agent
- Windows Phone 8 : Scheduled Tasks - To-Do List Scheduled Task Sample (part 5) - Editing an Existing To-Do Item
- Windows Phone 8 : Scheduled Tasks - To-Do List Scheduled Task Sample (part 4) - Creating the To-Do Item Shell Tile, Saving a To-Do Item
- Windows Phone 8 : Scheduled Tasks - To-Do List Scheduled Task Sample (part 3) - Debugging Scheduled Tasks
- Windows Phone 8 : Scheduled Tasks - To-Do List Scheduled Task Sample (part 2) - TodoService, TodoItemViewModel
- Windows Phone 8 : Scheduled Tasks - To-Do List Scheduled Task Sample (part 1) - TodoItem,TodoDataContext
- Windows Phone 8 : Scheduled Tasks - Using Scheduled Tasks
- Windows Phone 8 : Scheduled Tasks - Background Agent Types
- Windows Phone 8 : Windows Phone Toolkit Animated Page Transitions - Reusing the Transition Attached Properties
 
 
Windows XP
Windows Vista
Windows 7
Windows Azure
Windows Server
Windows Phone
2015 Camaro