Feature - the most used customization component in WSS and MOSS 2007

In this article we will discuss about the features in WSS / MOSS 2007. Features are the most used customization component in WSS and MOSS 2007. They provide the ability to package different functionalities in one feature and to deploy and install it to SharePoint server. In this article we will see the internal structure of the Feature and then we walkthrough to develop a custom feature to add a new menu item in the Custom List's Actions menu.

Features in Office SharePoint Server 2007: Overview

Microsoft Office SharePoint Server 2007 and Windows SharePoint Services 3.0 are known for their template framework which uses the XML files for customizations. By this exiting and enhanced template framework customizations to the Microsoft Office SharePoint Server 2007 / WSS 3.0 site are so much easy. Among this template framework Features are one of the major contributor. Features allow the facility to test, deploy and activate custom functionality inside WSS or Office SharePoint Server 2007. This also provides the facility to make the functionality available across the server farm as well. The functionalities may be a custom workflow, creating new custom content types, or adding new custom action to list tool bar or to add new page link to Site Actions menu. For example, you can package a custom list definition and deploy to any number of site as Feature, complete with its metadata in the schema or you can add a custom developed workflow to the site packaged in feature and later activating the feature. You can package the Feature as a SharePoint solution like .wsp and provide it to the system administrator to install and deploy it.

Other benefit of using the Features is that, it helps out to reduce the complexity of site definition (ONET.xml) files. ONET.xml files are the main site definition files which are used to create new sites in SharePoint. These files can be modified to meet the requirements. These files include the definition and default implementation information about lists and document libraries being included in new provisioned site, its navigation pattern, the features to be activated when the site is provisioned. With the use of features, the ONET.xml file shrinks because features can contain the information in separate file and referenced in the ONET.xml file. So this reduces the complexity of the ONET.xml file and makes it more manageable.

In this article we will create a custom Feature, which will add a new action item to the Actions menu of the Custom List and provides the functionality to redirect the user to the custom page where he will be provided with the functionality to move the list item attachments to a new document library. Before diving in to the custom feature development and implementation, we will discuss the basics of Features.

Internal Structure of a Feature

Feature is stored on the SharePoint Server at C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES directory. As you can see in the below image each and every feature has its own directory under the FEATURES directory. Each individual directory for feature at least contains two files: one is features.xml which guides the SharePoint for where to find the XML data and code that defines the Feature. The feature.xml file contains the Feature element that has the information about location of assemblies, files, dependencies or properties that support the Feature. Generally, the feature.xml file points to the element XML file that contains the definition of components and types that make the Feature. This file is generally stored with name as elements.xml. Most of the feature definitions have these two files and with name feature.xml and elements.xml. So to avoid lost of information of the other feature and to avoid overwriting of the information each feature has its own directory.



The Feature.xml file

The metadata associated with Feature are stored in the feature.xml file. The structure of the feature.xml file used for our example is as follows:

<?xml version="1.0" encoding="utf-8"?>
<Feature  Id="f5702592-4b51-4759-9eda-a4e6b12e566c"
           
Title="Copy or Move Attachments to Document Library"
           
Description="Provides the facility to move or copy attachments from custom
                      list items to document library."
           
Version="12.0.0.0"
           
Hidden="FALSE"
          
Scope="Web"
          
DefaultResourceFile="core"
          
ReceiverAssembly="CopyMoveAttachmentsFeature, Version=1.0.0.0, Culture=neutral,
                            PublicKeyToken=79f97b311651d47e"
          
ReceiverClass="CopyMoveAttachmentsFeature.CopyMoveAttachmentsFeature"
           
xmlns="http://schemas.microsoft.com/sharepoint/">
  <ElementManifests>
    <ElementManifest Location="elements.xml"/>
  </ElementManifests>
</Feature>


And the following is the sort but useful information of metadata items which are contained in the <Feature> element in the Feature.xml file.

The ID attribute is used to uniquely identify the Feature among other features on the server. The Title is displayed on the page for Site Features in the Site Settings section for a SharePoint site. The Description provides details about its functionality and displayed below the Title on Site Features Page. Generally in SharePoint provisioned site this description value is retrieved from the resource file. This helps in localization of the site. The Version is the current implemenation or development version of the feature. Generally 12.0.0.0 is used to match the current version of other SharePonit assemblies and SharePoint provided feature. But you can provide it of yours as well. Now, the Scope defines the context in which the Feature can be activated or deactivated. The scope value Web allows the Feature to activated or deactivated within the context of the site. The scope value Site allows the Feature to be activated or deactivated at the Site Collection context. The feature with scope of Site is displayed on the Site Collection Features page. There are also two other scope value: WebApplication and Farm. The Hidden indicates the features visibility on the Site Features page. If it is set to TRUE, the the feature will be displayed on the Site Features page, otherwise not. This is the Boolean value property and the allowed values are TRUE or FALSE. The optional but useful DefaultResourceFile attribute indicates the resource file used for the feature. The ImageUrl contains the relatiev path of the image which will be displayed next to the Feature Title on the Site Features page. The <ElementManifests> node houses the <ElementManifest> elements or nodes, where each <ElementManifest> element has the location, mostly relative, of the manifest file generally named elements.xml.

The following lines are from the elements.xml manifest file which is used for our example. The manifest file contains details of the different components or actions that make the real Feature. For example, the manifest to add a custom action item to the Actions Menu of a custom list and the UrlAction element for where to redirect when that custom action item is clicked.

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <CustomAction Id="CopyMoveAttachmentsToDocumentLibrary"
                 
GroupId="ActionsMenu"
                 
Location="Microsoft.SharePoint.StandardMenu"
                 
Sequence="100"
                 
Title="Copy or move attachments to document library"
                 
Description="Copy or move attachments of list items to document library"
                  
ImageUrl="_layotus/images/CREATE.GIF">
    <UrlAction Url="_layouts/CopyMoveAttachmentsToDocLib.aspx?ListId={ListId}"></UrlAction>
  </CustomAction>
  <Module Path="PageTemplate" Url="_layouts">
    <File Url="CopyMoveAttachmentsToDocLib.aspx" />
  </Module>
</Elements>

One more functionality provided by features is the EventHandlers which provide the developer to write code against the WSS/MOSS object model for applying changes to the site. For example, when the Feature is activated, the site title can be changed or a new list can be created. Generally, Features provide following main four Events:
     1. FeatureActivated: This event is triggered when the feature is activated on the site or site collection.
     2. FeatureDeactivating: This event is triggered when the feature is being deactiated from the site.
     3. FeatureInstalled: This event is triggered when the feature is successfully installed on the server.
     4. FeatureUninstalling: This event is triggered when the feature is being uninstalled from the server.

To use this events in your feature development, you have to create a class which inherit from SPFeatureReceiver base class, and the have to override the above said four method of the base class. In the overridden method you can wrap your logic of changes to be applied to the site. The following code snippet shows you the structure of the CopyMoveAttachmentsFeature class which is inherited from SPFeatureReceiver.

public class CopyMoveAttachmentsFeature : SPFeatureReceiver
    {
        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            SPWeb _web = SPContext.Current.Web;
            _web.Properties["OldTitle"] = _web.Title;
            _web.Title = _web.Title + " with Copy or move attachments feature activated";
            _web.Update();
        }

         public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            SPWeb _web = SPContext.Current.Web;
            _web.Title = _web.Properties["OldTitle"];
            _web.Update();  
        }

         public override void FeatureInstalled(SPFeatureReceiverProperties properties)
        {
              //To do code
        }

         public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
         {
             //To do code
        }
    }


The above code also shows you the example how to change the web site title when the feature is activated and also to restore the old title when the feature is deactivated.

Install the Feature

When the development of the feature is completed you need to install and activate the feature. You can install and activate the feature by two ways. You have to perform the below steps to install and activate the feature on the server. Here the directory name is the one which is going to be developed later. You need to change it as per your feature directory name.

1. Coyp the folder which contains the feature files, i.e. feature.xml and elements.xml to C:\PROGRAM FILES\COMMON FILES\MICROSOFT SHARED\WEB SERVER EXTENSIONS\12\TEMPLATE\FEATURES directory.
2. Open the Command prompt.
3. Execute “stsadm –o installfeature –filename CopyMoveAttachmentsFeature\feature.xml –force” to install the feature on the server.
4. Execute “stsadm –o activatefeature –name CopyMoveAttachmentsFeature    –url http://localhost:2000 –force” to activate the feature for the particular site as shown in command.

Now we will see the real world example as a case study.

Case Study: Creating Custom Feature to move or copy attachments to document library

Requirements: We need the functionality which provide the user to move or copy the attachment documents which are attached while create list item. So, we need a menu item in Actions menu of the list which will redirect the user to the page where he can select the attachment documents from the list. He can also have the option to select the existing document library or to craete a new document library. Also, he will be provided the option to move all the attachment documents or to move just selected documents to the new or existing document library. For our purpose we are using Custom Lists. So, we need this functionality on ever custom lists which are created in the site. Also, this functionlity will be activated and deactivated when needed and limited to the single site as well.

Development scenario: To fullfill the requirements the best way is to create a feature which provide the functionality, that when it is activated on the particular site, a new menu item is being added to the Actions menu of the each instances of the Custom List type. So, we perform the following steps to reach to our goal.

1. Create a class library project in Visual Studio 2005 or Visual Studio 2008.

2. Add reference of Microsoft.SharePoint.dll to the project.

3. Next, create the folder heirarchy like 12\TEMPLATE\FEATURES in the project. See below image.

4. Now, create a new folder under FEATURES folder in project and name it CopyMoveAttachmentsFeature. This is the folder which is copied to the Windows SharePoint Services FEATURES directory when installing the feature.

5. Now in the CopyMoveAttachmentsFeature folder, add a new xml file and name it feature.xml.

6. Now, in the feature.xml file, write the following text to define the Feature element.

7. As per the above xml file content, you can see that the Feature element has several attributes like ID – a GUID to uniquely identify the feature on the server, Title – valid descriptive name of the feature which will be displayed on Site Features page, Version – the version of the feature, generally, 12.0.0.0, Scope – here “Web” which defines the context where the feature be activated or deactivated. Other attributes ReceiverAssembly and ReceiverClass are optional and required if you want to attach the Event handler for the feature to you feature. The ElementManifest node of ElementManifests element points the location of the elements.xml file which will be creaed in the next point.

8. Now create one new xml file in the same CopyMoveAttachmentsFeature folder and name it elements.xml. If you provide different name then you have to change the Location attribute value of the ElementMainfes element in the feature.xml file to avoid any error.

9. Now, open the elements.xml file, if not an write the below text to craete Elements.

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <CustomAction Id="CopyMoveAttachmentsToDocumentLibrary"
                 
GroupId="ActionsMenu"
                 
Location="Microsoft.SharePoint.StandardMenu"
                 
Sequence="100"
                 
Title="Copy or move attachments to document library"
                 
Description="Copy or move attachments of list items to document library"
                  
ImageUrl="_layotus/images/CREATE.GIF">
    <UrlAction Url="_layouts/CopyMoveAttachmentsToDocLib.aspx?ListId={ListId}"></UrlAction>
  </CustomAction>
  <Module Path="PageTemplate" Url="_layouts">
    <File Url="CopyMoveAttachmentsToDocLib.aspx" />
  </Module>
</Elements>

10. As seen in the above text, the CustomAction element in Elements node, has Id – an id of custom action, GroupId – the id of the group where to display the CustomAction item, here we have provided “ActionsMenu”, Title – a valid descriptive name of the action to be displaed in the Actions menu item, ImageUrl – relative url of the image for the menu item. The UrlAction element of CustomAction provide the relative path to the page where the user is being redirected when he clicks the item in Actions menu.

11. Now our feature is ready to install and to be activated. But our main functionality resided in the page CopyMoveAttachmentsToDocLib.aspx.

12. To create a custom page, first create a new folder under the TEMPLATE directory.

13. In that folder add a new aspx page with name CopyMoveAttachmentsToDocLib.aspx.

14. Add the below lines to the page which you just created. Please download the working sample to see the full code of the example.

<%@ Assembly Name="CopyMoveAttachmentsFeature, Version=1.0.0.0, Culture=neutral,PublicKeyToken=79f97b311651d47e" %>
<%@ Page Language="C#" MasterPageFile="~/_layouts/application.master" EnableViewState="true" AutoEventWireup="true" Inherits="CopyMoveAttachmentsFeature.CopyMoveAttachmentsToDocLibForm" %>
<%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls"
    Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="jatin" TagName="ucCopyMoveAttachments" Src="~/_controltemplates/CopyMoveAttachmentsToDocLib/ucCopyMoveAttachmentsToDocLib.ascx" %>
<asp:Content ID="PageTitle" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
    <%= PageTitle %>
</asp:Content>
<asp:Content ID="PageTitleInTitleArea" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea"
    
runat="server">
    <%= PageTitleInArea %>
</asp:Content>
<asp:Content ID="PageDescription" ContentPlaceHolderID="PlaceHolderPageDescription"
    
runat="server">
    <%= PageDescription %>
</asp:Content>
<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
    <jatin:ucCopyMoveAttachments ID="control1" runat="server"></jatin:ucCopyMoveAttachments>    
</asp:Content>

15. Now, as shown in the above code line, the page uses the user control named ucCopyMoveAttachments. This is the main user control that performs all the required actions.

16. So, using the user control in the custom page, is one of the ways to develope the custom pages for SharePoint. Others are using Web Part, using inline coding for custom page and using custom controls.

17. Now add a new folder in the project named CONTROLTEMPLATES under the TEMPLATE folder. And in that add a new user control and name is "ucCopyMoveAttachmentsToDocLib.ascx". See the below image.



18.   We will not see each and every line of the code. But you can download the full working source code of this sample.

19.    The method GetListItemAttachments() given below get the all attachments attached with each item of the list. The list information is based on the query string parameter ListId. This ListId value is passed from out custom menu item added in the Actions Menu of the list.

private void GetListItemAttachments()
    {
        SPQuery query = new SPQuery();
        query.Query = "<OrderBy><FieldRef Name='Title' /></OrderBy>";
        SPListItemCollection items = _list.GetItems(query);
        foreach (SPListItem item in items)
        {
            SPAttachmentCollection attachments = item.Attachments;
             for (int i = 0; i < attachments.Count; i++)
            {
                DataRow dr = Attachments.NewRow();
                 dr["ItemID"] = item.ID;
                 dr["ItemTitle"] = item.Title;
                 dr["AttachmentName"] = attachments[i];
                 dr["AttachmentUrl"] = string.Format("{0}{1}", attachments.UrlPrefix, attachments[i]);
                 Attachments.Rows.Add(dr);
            }
        }
        gvItems.DataSource = Attachments;
        gvItems.DataBind();
    }

20.    Below image will give the idea about how the custom page works for moving or copying the attachments.



21.    As shown in the above image, the user is provided with the options to move or copy the attachments, also that he wants to move / copy all the attachments or only selected. The user is also presended with the list of existing document libraries in the current site to selected for moving or copying the attachment. If the user want to created the new document library the he can select the option for that and provide the name of the document library as well. For out example, by default a new document library is being created with the provided name.

22. When the user clicks "Ok" button, based on the selection of this options, the remaing operations are performed. The method MoveSelectedAttachments() ,as shown below, moves or copies the selected attachments to the existing or new document library. If the user has selected "Move" action, then selected attachment(s) are deleted from the item's attachments collection.

private void MoveSelectedAttachments(string newDocLibName, string newDocUrl)
    {
        bool found = false;
        foreach (GridViewRow row in gvItems.Rows)
        {
            CheckBox cb = row.FindControl("chkSelect") as CheckBox;
             if (!cb.Checked)
                 continue;
            found = true;
            string fileName = ((Label)row.FindControl("lblAttachmentName")).Text;
            string filePath = string.Format("{0}/{1}/{2}", _web.Url.Trim('/'), newDocLibName, fileName);
            SPFile attachment = _web.GetFile(((Label)row.FindControl("lblAttachmentUrl")).Text);
             _web.Files.Add(filePath, attachment.OpenBinary(), true);
            if (rblAction.SelectedItem.Text.Equals("Move"))
            {
                SPListItem item = _list.GetItemById(Convert.ToInt32(((Label)row.FindControl("lblItemID")).Text));
                 item.Attachments.RecycleNow(fileName);
             }
         }
         if (found)
        {
            lblResult.Text = string.Format("Selected attachment(s) are {0} to {1}",
                 rblAction.SelectedItem.Text.Equals("Copy") ? "Copied" : "Moved", string.Format("<a href='{0}'>{1}</a>", newDocUrl, newDocLibName));
        }
        else
            lblResult.Text = "Please select attachment(s) to " + rblAction.SelectedItem.Text.ToLower();
    }

23. The method MoveAllAttachments(), as shown below, moves or copies all the attachments to the existing or new document library. In this method also, if the user has selected "Move" action, then all the attachments for all the items are deleted and sent to the recycle bin.

private void MoveAllAttachments(string newDocLibName, string newDocUrl)
    {
        foreach (DataRow dr in Attachments.Rows)
        {
            string fileName = dr["AttachmentName"].ToString();
            string filePath = string.Format("{0}/{1}/{2}", _web.Url.Trim('/'), newDocLibName, fileName);
            SPFile attachment = _web.GetFile(dr["AttachmentUrl"].ToString());
             _web.Files.Add(filePath, attachment.OpenBinary(), true);

             if (rblAction.SelectedItem.Text.Equals("Move"))
            {
                SPListItem item = _list.GetItemById(Convert.ToInt32(dr["ItemID"]));
                item.Attachments.RecycleNow(fileName);
            }
        }
        lblResult.Text = string.Format("All attachment(s) are {0} to {1}",
            rblAction.SelectedItem.Text.Equals("Copy") ? "Copied" : "Moved", string.Format("<a href='{0}'>{1}</a>", newDocUrl, newDocLibName));
    }

Installing the working feature using .bat file

Before going to the process of creating and executing the batch file, we must need to sign our assembly with strong name. So, to do that, right click the project name in the Solution explorer and click properties. On the properties page click "Signing" tab, see below image. Check the "Sign the assembly" and from the "Choose a strong name key file:" drop down, select <New...>. This will open a new dialog to create Strong Name Key. There provide proper name for the file, clear the "Protect my key file with a password" check box and click Ok. Now, save the project and build.



Using the batch command file, you can execute multiple command at the cost of single command. So, add a new batch file named "install.bat" at the project level. See, the above image of the project structure for more information. In that file write the following lines.

@SET STSADM="c:\program files\common files\microsoft shared\web server extensions\12\bin\stsadm"
@SET GACUTIL="c:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe"

Echo Installing HelloWorld.dll in GAC
%GACUTIL% -if bin\debug\CopyMoveAttachmentsFeature.dll

Echo Copying files to TEMPLATE directory

xcopy /e /y 12\TEMPLATE\* "c:\program files\common files\microsoft shared\web server extensions\12\Template"

Echo uninstalling feature if installed previously
%STSADM% -o uninstallfeature -name CopyMoveAttachmentsFeature -force

Echo Installing feature
%STSADM% -o installfeature -filename  CopyMoveAttachmentsFeature\feature.xml -force

IISRESET


Now, execute the batch file. This will first adds, the assembly / dll, CopyMoveAttachmentsFeature.dll, to the GAC. the copies all the content of the TEMPLATE folder to the TEMPLATE directory of 12 hive, of SharePoint. Then it tries to uninstall the feature, if it is installed previously using "STSADM -o uninstallfeature -name CopyMoveAttachmentsFeature -force" command. Then using the "STSADM -o installfeature -filename  CopyMoveAttachmentsFeature\feature.xml -force" command it installs the feature to the SharePoint Server. This is the actual operation that informs the SharePoint Server about our custom feature. And at the last IISRESET is performed, to take chagnes in the effect.

Experience the Feature working in real SharePoint Site

To see actual working of the feature, Navigate to your SharePoint site or create a new site.

Now, go to Site Settings page. There click on "Site Features". This will take you to the Site Features page, as shown below.



There, locate the Feature with name "Copy or Move Attachments to Document Library" or which you provided, and Activate it.

Now, if there is any existing custom list, then go to there or create a new custom list. There click the Action menu from the list's tool bar, There you can see, that our custom action with name "Copy or Move Attachments to Document Library".



For testing, add couple of item to the list with the attachments.

After that by clicking "Copy or Move Attachments to Document Library" on the Actions menu, you will be redirected to our custom page. And there you can test the functionality. Rest is leaved to the reader.........


I hope you have enjoyed the article and learned about features, custom pages and working with document library and lists as well as working with attachments of the list. You can download the fully working code from below link.

Source code for CopyMoveAttachmentsFeature.

By Jatin Prajapati   Popularity  (1774 Views)
Picture
Biography - Jatin Prajapati
I think, most of the people are interested only in answers so no Biography provided... Want know more just write me at jatin.prajapati.er@gmail.com