A few months ago I created a CodePlex project that allows you to configure a library to allow the storing of web part page history. The project at its core used three item event receivers to listen to certain key events and either backup the page or restore the page based on the event. Recently I was thinking about what might be the best way to allow people to script the settings that enable the storing of page history. I decided that I would start off by providing a simple STSADM command that would allow you to script the adding of event receivers to a list (fortunately making it work for webs and content types didn’t really require any additional work so I covered those as well). The new command I created is called gl-addeventreceiver.

I’ll probably eventually come up with something else but this at least is a start – I primarily don’t like it because it requires that people know how the web part history project works so I’ll probably create a command specific to enabling the history so that it abstracts out the technical details which could always change (there just hasn’t been a whole lot of interest in the project so I’ve not really spent much time on it). In the meantime this command is a nice generic tool that could be used by developers and administrators for various reasons (I’ll probably create an enum and remove command to supplement this one – just haven’t gotten around to it yet).

Adding an event receiver via code is really very simple – just a matter of calling the Add method of the SPEventReceiverDefinitionCollection object which you can get via the EventReceivers property of either the SPList, SPContentType, or SPWeb object. To get an existing event receiver (to check for existence as we don’t want to add twice) we have to loop through the collection comparing the assembly name, class name, and event receiver type.

 1/// <summary>
 2/// Adds an event receiver to the specified target
 3/// </summary>
 4/// <param name="url">The URL.</param>
 5/// <param name="contentTypeName">Name of the content type.</param>
 6/// <param name="target">The target.</param>
 7/// <param name="assembly">The assembly.</param>
 8/// <param name="className">Name of the class.</param>
 9/// <param name="type">The type.</param>
10/// <param name="sequence">The sequence.</param>
11/// <param name="name">The name.</param>
12public static void Add(string url, string contentTypeName, TargetEnum target, string assembly, string className, SPEventReceiverType type, int sequence, string name)
14    using (SPSite site = new SPSite(url))
15    using (SPWeb web = site.OpenWeb())
16    {
17        SPEventReceiverDefinitionCollection eventReceivers;
18        if (target == TargetEnum.List)
19        {
20            SPList list = Utilities.GetListFromViewUrl(web, url);
22            if (list == null)
23            {
24                throw new Exception("List not found.");
25            }
26            eventReceivers = list.EventReceivers;
27        }
28        else if (target == TargetEnum.Site)
29            eventReceivers = web.EventReceivers;
30        else
31        {
32            SPContentType contentType = null;
33            try
34            {
35                contentType = web.AvailableContentTypes[contentTypeName];
36            }
37            catch (ArgumentException)
38            {
39            }
40            if (contentType == null)
41                throw new SPSyntaxException("The specified content type could not be found.");
43            eventReceivers = contentType.EventReceivers;
44        }
45        SPEventReceiverDefinition def = Add(eventReceivers, type, assembly, className, name);
46        if (sequence >= 0)
47        {
48            def.SequenceNumber = sequence;
49            def.Update();
50        }
51    }
54/// <summary>
55/// Adds an event receiver to a the specified event receiver definition collection.
56/// </summary>
57/// <param name="eventReceivers">The event receivers.</param>
58/// <param name="eventReceiverType">Type of the event receiver.</param>
59/// <param name="assembly">The assembly.</param>
60/// <param name="className">Name of the class.</param>
61/// <param name="name">The name.</param>
62/// <returns></returns>
63private static SPEventReceiverDefinition Add(SPEventReceiverDefinitionCollection eventReceivers, SPEventReceiverType eventReceiverType, string assembly, string className, string name)
65    if (GetEventReceiver(eventReceivers, eventReceiverType, assembly, className) == null)
66    {
67        eventReceivers.Add(eventReceiverType, assembly, className);
68        SPEventReceiverDefinition def = GetEventReceiver(eventReceivers, eventReceiverType, assembly, className);
69        if (!string.IsNullOrEmpty(name))
70        {
71            def.Name = name;
72            def.Update();
73        }
74        return def;
75    }
76    return null;
79/// <summary>
80/// Gets the event receiver.
81/// </summary>
82/// <param name="eventReceivers">The event receivers.</param>
83/// <param name="eventReceiverType">Type of the event receiver.</param>
84/// <param name="assembly">The assembly.</param>
85/// <param name="className">Name of the class.</param>
86/// <returns></returns>
87private static SPEventReceiverDefinition GetEventReceiver(SPEventReceiverDefinitionCollection eventReceivers, SPEventReceiverType eventReceiverType, string assembly, string className)
89    foreach (SPEventReceiverDefinition erd in eventReceivers)
90    {
91        if (erd.Assembly == assembly && erd.Class == className && erd.Type == eventReceiverType)
92        {
93            return erd;
94        }
95    }
96    return null;

The help for the command is shown below:

C:\>stsadm -help gl-addeventreceiver

stsadm -o gl-addeventreceiver

Adds an event receiver to a list, web, or content type.

        -url <web or list URL>
        -assembly <assembly>
        -class <class name>
        -type <itemadding | itemupdating | itemdeleting | itemcheckingin | itemcheckingout | itemuncheckingout | itemattachmentadding | itemattachmentdeleting | itemfilemoving | fieldadding | fieldupdating | fielddeleting | sitedeleting | webdeleting | webmoving | itemadded | itemupdated | itemdeleted | itemcheckedin | itemcheckedout | itemuncheckedout | itemattachmentadded | itemattachmentdeleted | itemfilemoved | itemfileconverted | fieldadded | fieldupdated | fielddeleted | sitedeleted | webdeleted | webmoved | emailreceived | contextevent | invalidreceiver>
        -target <site | list | contenttype>
        [-contenttype <content type name if target is ContentType>]
        [-sequence <sequence number>]
        [-name <the name to give to the event receiver>]

The following table summarizes the command and its various parameters:

Command NameAvailabilityBuild Date
gl-addeventreceiverWSS v3, MOSS 2007Released: 9/13/2008
Parameter NameShort FormRequiredDescriptionExample Usage
urlYesThe URL to the web or list to add the event receiver to.-url http://portal/pages
assemblyaYesThe fully qualified assembly name containing the event receiver class to add.-assembly "Lapointe.WebPartPageHistory, Version=, Culture=neutral, PublicKeyToken=3216c23aba16db08", -a "Lapointe.WebPartPageHistory, Version=, Culture=neutral, PublicKeyToken=3216c23aba16db08"
classcYesThe fully qualified class name of the event receiver to add.-class Lapointe.WebPartPageHistory.ListEventReceivers.SourceListEventReceiver, -c Lapointe.WebPartPageHistory.ListEventReceivers.SourceListEventReceiver
typeYesThe event type to add. The command does not validate that you are adding the correct type for the specified target or that the specified class contains handlers for the type specified.-type itemupdated
targetNoThe target type to add the event receiver to. Must be either “list”, “site”, or “contenttype”. If omitted defaults to “list”.-target list
contenttypectNo, unless target is contenttypeThe name of the content type to add the event receiver to if the target is contenttype.-contenttype "Page", -ct "Page"
sequenceseqNoThe sequence number specifies the order of execution of the event receiver.-sequence 1000, -seq 1000
namenNoThe name to give to the event receiver. The name has no significance but can be useful when later listing the event receivers.-name "Handle Saving of Page History", -n "Handle Saving of Page History"

The following is an example of how to add three event receivers to a pages library – the three commands illustrated below constitute the required event receivers that must be enabled to turn on the web part page history:

stsadm -o gl-addeventreceiver -url http://portal/pages -assembly "Lapointe.WebPartPageHistory, Version=, Culture=neutral, PublicKeyToken=3216c23aba16db08" -class "Lapointe.WebPartPageHistory.ListEventReceivers.SourceListEventReceiver" -target list -sequence 1000 -type itemcheckedin

stsadm -o gl-addeventreceiver -url http://portal/pages -assembly "Lapointe.WebPartPageHistory, Version=, Culture=neutral, PublicKeyToken=3216c23aba16db08" -class "Lapointe.WebPartPageHistory.ListEventReceivers.SourceListEventReceiver" -target list -sequence 1000 -type itemupdating

stsadm -o gl-addeventreceiver -url http://portal/pages -assembly "Lapointe.WebPartPageHistory, Version=, Culture=neutral, PublicKeyToken=3216c23aba16db08" -class "Lapointe.WebPartPageHistory.ListEventReceivers.SourceListEventReceiver" -target list -sequence 1000 -type itemupdated