Saturday, October 10, 2009

Common actions feature receiver

We all know about the standard SharePoint feature elements – Module, Field, ContentType, ContentTypeBinding, ListInstance, etc. Still in many cases there are tasks we want to achieve for which we need to use feature receivers and use custom code to do one thing or another. Many of these tasks are quite common and recurring so it is obviously wise to have some XML configuration that can be reused in the various features that we have and handled by a common feature receiver. The most natural thing would be to extend somehow the standard elements though it’s not possible to have both standard and custom elements in one and the same manifest file. Actually we can’t place non-standard elements in an element manifest file but we can have another configuration file (or files) that the feature or the feature receiver knows about and can process its elements when the feature gets activated. And this is what I started developing (I say starting because I intend to extend it with other features in the future) – a custom XML configuration format and a custom feature receiver that handles it.

So, first a word about what “common actions” I have put in this feature receiver – the first one is quite versatile – it sets various settings to SharePoint lists – it allows to set most of the properties of the SPList class, to add site columns and content types to the list, to order and hide the content types, to create views in the list, etc. The second one is rather simple – it sets up the lookup site columns that you have – something that can’t be achieved with the standard Field element.

One step back now – about the “common action” that sets the various SPList settings – I guess that you have already asked yourself why have such an element since we have the standard ListTemplate element and can create custom list definition features with all schema configurations for a custom list. There are several reasons for that (at least these are the things that made be stop using custom list templates): the first one is that the list template is applicable only for lists that are about to be created – you can’t use them to change anything on existing lists, second – they are rather uneconomical – if you wish to extend a list based on a standard list template with a couple of fields and one or two list views you need to create a separate list definition. Imagine what happens when you need 20 or so different lists (I was quite disappointed when I found out that the standard ListInstance element allows adding data to the list but not changing its schema).

About the available for downloading solution – besides the receiver’s code it contains also an XSD file used for validation of the “common actions” XML – it is actually an extension of the standard WSS schema definitions (which are somewhat incomplete actually) – the list view and field schema definitions are actually reused from the standard definitions – you will see shortly. One other big advantage of having an XML schema definition is that you can use the Visual Studio’s editor with all goodies like IntelliSense, inline validation, etc – there is a VS configuration XML file in the project that if put in the appropriate VS installation folder enables that (see below in the installation notes). There is also a console tool project in the solution – this tool can be used to generate a feature containing the list settings for one, several or all lists from an existing site – something like a reverse engineering utility which can speed up greatly the development process. The feature that is generated contains a standard elements manifest file with ListInstance elements for the specified lists – so basically this feature when applied to a new site will create the lists from the source “snapshot” and will add the various customizations that were applied to them.

And here are the XMLs of a sample feature that uses the common action provider:

<?xml version="1.0" encoding="utf-8"?>

<Feature Title="my feature" Description="my feature" Id="699b4ad2-c77e-440c-a488-b569d71e3467" Scope="Web" Hidden="TRUE" DefaultResourceFile="core"

         ReceiverAssembly="Stefan.Sharepoint.Util, Version=1.0.0.0, Culture=neutral, PublicKeyToken=338fd4db0d2cb397"

         ReceiverClass="Stefan.Sharepoint.Util.FeatureReceivers.CommonActionsReceivers" xmlns="http://schemas.microsoft.com/sharepoint/">

  <ElementManifests>

    <ElementManifest Location="elements.xml" />

  </ElementManifests>

  <Properties>

    <Property Key="CommonActionsPath" Value="commonactions.xml" />

  </Properties>

</Feature>

this is the sample feature.xml file – the ReveiverAssembly and ReceiverClass attributes of the Feature element are set accordingly and there is a Property element with Key attribute set to “CommonActionsPath”, whose value contains the relative path within the feature folder of the “common actions” configuration XML.

And this is a sample “common actions” configuration XML:

<?xml version="1.0" encoding="utf-8"?>

<CommonActions xmlns="http://schemas.microsoft.com/sharepoint/" >

 

  <ListSettings ListUrl="Lists/Action">

    <ListProperties Title="Actions" EnableVersioning="TRUE" EnableModeration="TRUE" />

    <Fields>

      <FieldRef ID="282d1240-b8d5-4862-b9ff-940e170cc7b2" Name="ActionID" />

      <FieldRef ID="6810bdee-f664-4a9f-b58c-39329fb8036e" Name="ActionExpireDate" />

      <FieldRef ID="3964fd24-5908-40cd-9822-9271b2e5dad7" Name="ActionImage" />

      <FieldRef ID="a16c3c60-5782-4b70-a965-722ccf8cb32d" Name="ActionFlashFile" />

    </Fields>

    <View DisplayName="All Items" Type="HTML" DefaultView="TRUE">

      <Query>

        <OrderBy>

          <FieldRef Name="ActionExpireDate" Ascending="FALSE" />

        </OrderBy>

      </Query>

      <ViewFields>

        <FieldRef Name="Edit" />

        <FieldRef Name="LinkTitle" />

        <FieldRef Name="ActionID" />

        <FieldRef Name="ActionExpireDate" />

      </ViewFields>

      <RowLimit Paged="TRUE">100</RowLimit>

    </View>

  </ListSettings>

</CommonActions>

You see a CommonActions root element containing one ListSettings element – you can have many of these. Most of the attributes and elements a self explanatory and the FieldRef and View elements are actually identical to the standard WSS field and view definitions (I mentioned that the standard SharePoint XSDs are reused here).

So let me briefly explain the various XML elements and attributes that can be used within the ListSettings elements. Basically all sub-elements are optional, so you can use just a subset of these to apply the appropriate settings. You can use the ListUrl attribute in the ListSettings element to specify the SharePoint list that you want to modify. There is another alternative to specify the list to be customized – with it you can actually specify many lists – this is very handy if you want to apply the same settings to multiple lists, here is the syntax – you use a sub-element of the ListSettings element:

    <ListSelector All="FALSE">

      <ListUrls>

        <add ListUrl="Lists/mylist"/>

      </ListUrls>

      <ListTemplates>

        <add ListTemplate="100"/>

      </ListTemplates>

    </ListSelector>

You can specify either list URLs or list templates, besides add elements remove elements can also be specified to finely tune the set of lists that you want to work with.

The ListProperties sub-element can contain the following attributes:

<ListProperties Title="Actions" Description="" EnableVersioning="FALSE" EnableModeration="FALSE" EnableMinorVersions="FALSE" Direction="none" MajorVersionLimit="0" MajorWithMinorVersionsLimit="0" AnonymousPermMask64="0" AnonymousPermMask="0" AllowDeletion="TRUE" EnableDeployWithDependentList="TRUE" EnableDeployingList="TRUE" AllowMultiResponses="FALSE" EnableAttachments="TRUE" EnableFolderCreation="FALSE" ForceCheckout="FALSE" DraftVersionVisibility="Reader" DefaultItemOpen="PreferClient" Hidden="FALSE" ContentTypesEnabled="TRUE" MultipleDataList="FALSE" Ordered="FALSE" RequestAccessEnabled="TRUE" ShowUser="TRUE" AllowEveryoneViewItems="FALSE" ReadSecurity="1" WriteSecurity="1" OnQuickLaunch="TRUE" EnableAssignToEmail="FALSE" EnableSyndication="TRUE" IrmEnabled="FALSE" IrmExpire="FALSE" IrmReject="FALSE" EnableSchemaCaching="FALSE" NoCrawl="FALSE" SendToLocationName="" SendToLocationUrl="" />

The attributes bear the same names as the corresponding SPList class properties. Note here that the different types of lists doesn’t support the setting of some of the properties to values different from the default ones – and if you try to do that the properties’ setters will throw an exception.

The Fields sub-element can contain both Field and FieldRef elements:

    <Fields>

      <Field ID="{282D1240-B8D5-4862-B9FF-940E170CC7B2}" Name="ActionID" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="ActionID" Group="my group" Type="Text" DisplayName="Action id" Required="FALSE" MaxLength="255" />

      <FieldRef ID="6810bdee-f664-4a9f-b58c-39329fb8036e" Name="ActionExpireDate" />

    </Fields>

The Field element contains a standard WSS field definition and can be used to create a field in the list with the specified inline field schema. The FieldRef element can be used to add existing site columns to the list – only the ID attribute is used to locate the field in the site columns, the Name attribute is optional and its use is just to give a visual hint about the field’s name. Note here – if the list already exists and the field is already created in it the feature receiver takes no action and skips the field.

There are two sub-elements for applying content type settings to the list:

    <ContentTypeRefs>

      <ContentTypeRef Name="my content type"/>

    </ContentTypeRefs>

    <ContentTypeOrder>

      <ContentTypeRef Name="my content type"/>

      <ContentTypeRef Name="Item"/>

    </ContentTypeOrder>

The ContentTypeRefs element can be used to add existing content types to the list – basically the same as you can achieve with the standard ContentTypeBinding element – the difference here is that you specify the content type’s Name not ID. I added this doublet of the standard functionality in case it is used with the multiple list select option of the ListSettings element – if you want to add one or more content types to several lists simultaneously. Note here – if the content type is already added to the list – the feature receiver just skips it. The second sub-element – ContentTypeOrder – allows you to set the order of the content types as they appear in the “New” menu item of the SharePoint list.

The View sub-element (you can have more than one) contains a standard WSS View definition – you will quickly recognize the standard Query, ViewFields and RowLimit elements within it. Mandatory attributes in the View element are the DisplayName and Type ones. The view definitions are matched to the existing views in the list using the view’s display name. If a view with that name doesn’t exist it is created, otherwise the view definition is applied to the existing view.

After the brief description of the ListSettings “common action” I will describe the lookup field “common action” with one or two lines only – first – here’s a sample usage:

<LookupFieldSettings ID="efd8d109-4f6f-4828-ac32-d9f2e11f8669" Name="MyField" LookupListUrl="Lists/MyList" ShowField="Title" />

The field is located in the site columns using the field ID, the Name attribute is just a visual hint. The LookupListUrl attribute specifies the site relative URL of the lookup list and the ShowField attribute – the lookup source field in the lookup list. If the lookup field is already set up (its LookupList property is set) the receiver will skip it.

Using the command line tool to generate features from existing sites

This is a sample usage of the tool that generates a feature with standard elements manifest file containing ListInstance elements for several lists specified in the command line arguments and a common actions configuration file with settings for these lists:

UtilTest.exe -o exportlistfeature -weburl http://racoon-vpc-hg:2909 -listurl Lists/mylist,Lists/mylist2 -outputpath "c:\temp\myfeature" -exportfields -exportcontenttypes  -exportcontenttypeorder -dontusesitecolumns -featuretitle "my feature"

The syntax is pretty similar to the one of the standard stsadm utility – the parameters starting with a dash are argument names and the ones following each argument name are argument values (they are optional). These arguments are mandatory - -o, –weburl, –listurl, –outputpath and –featuretitle – their names are explanatory for their usage. The –listurl argument can contain one list URL only or several separated with commas, it can also contain the * (asterisk) character for all lists (without the hidden ones) in the site. The other arguments are optional: -exportfieldsexportcontenttypes and –exportcontenttypeorder specify whether the corresponding sub-elements in the ListSettings element should be exported and the –dontusesitecolumns argument specifies whether the custom list columns  should be exported with inline schemas or with FieldRef elements if identical site columns exist.

There is one other command of the export utility – the one that exports a feature for setting up the lookup fields for the specified site (actually for the site columns of the site collection whose lookup lists are in the specified site):

UtilTest.exe -o exportlookupfeature -weburl http://racoon-vpc-hg:2909 -outputpath "c:\temp\lookupfeature" -featuretitle "lookup feature"

Installation notes

  • the Stefan.Sharepoint.Util should be placed in the GAC (this is only if you use the receiver class from it otherwise you can copy the code to some assembly of yours)
  • the contents of the 12 folder of the solution should be copied to your SharePoint’s 12 folder. It actually contains one XSD file only - stefan.common.xsd which should be copied to the SharePoint’s 12\TEMPLATE\XML folder.
  • the file stefan.xml from the root of the solution should be copied to the Xml\Schemas subfolder of your Visual Studio’s installation folder (for VS 2008 it’s normally C:\Program Files\Microsoft Visual Studio 9.0\Xml\Schemas). After you copy the file there and restart your Visual Studio you will have the IntelliSense support for the “common actions” XML format.
  • the command line utility UtilTest.exe uses the Stefan.Sharepoint.Util assembly so you need to have the two files together if you want to use it (unless the Stefan.Sharepoint.Util assembly is in the GAC of the machine).

You can download the common actions receiver code from here.

No comments:

Post a Comment