DCSIMG
SharePoint – Events are duplicated when using templates - David Birin's blog

SharePoint – Events are duplicated when using templates

I encountered a strange behavior in SharePoint, this phenomenon happens when you create an event handler and attach it to a list template (for example, a document library) using a web-site level feature. If you save the list as template, the event handler reference is saved inside the list template (STP file) and when you create an instance using the template it can cause the following problems:

  1. The event handler will be activated automatically on a web site where the feature is not enabled.
  2. If the event feature is enabled in the web site the event will pop twice (or more if a list with duplicated events will be saved as template…)

Now for proving this point I will attach some code samples which demonstrate the above, and a solution to the problem.

I created a sample Event Handler, which adds the text “From event handler [THE CURRENT TIME] to the Title field:

public class SampleEvent : SPItemEventReceiver
{
    public override void ItemAdded(SPItemEventProperties properties)
    {
        try
        {
            this.DisableEventFiring();
 
            //Get the context item
            using (SPWeb contextWeb = properties.OpenWeb())
            {
                SPList contextList = contextWeb.Lists[properties.ListId];
                SPListItem contextItem = contextList.GetItemById(properties.ListItemId);
                //Sample update for testing
                contextItem["Title"] += "From event handler " + DateTime.Now.ToShortTimeString();
                contextItem.SystemUpdate(false);
            }
        }
        finally
        {
            this.EnableEventFiring();
        }
    }
 
}

I registered it using the following feature:

Feature.xml:

<?xml version="1.0" encoding="utf-8" ?>
<Feature Id="227EEA0A-D42F-4ab7-84DF-E31406A98AFD" 
Title="Sample event handler feature"
Description="Used for testing eventviewer"
Version="1.0.0.0"
Scope="Web"
Hidden="False"
AlwaysForceInstall="TRUE"
ImageUrl=""          
xmlns="http://schemas.microsoft.com/sharepoint/">
    <ElementManifests>
        <ElementManifest Location="event.xml" />
    </ElementManifests>
</Feature>

event.xml:

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
    <Receivers ListTemplateId="101">
      <Receiver>
          <Name>SampleEvent</Name>
          <Type>ItemAdded</Type>
          <SequenceNumber>1000</SequenceNumber>
          <Assembly>SampleEvent, Version=1.0.0.0, Culture=neutral, PublicKeyToken=392ad9e36e9f08a3</Assembly>
          <Class>SampleEvent.SampleEvent</Class>
          <Data></Data>
      </Receiver>       
</Receivers>
</Elements>

I activated the feature (web-site level):

image

and uploaded a document to a document library in a site, as seen in the next screenshot the event did it’s job:

image

Now, I saved the document library as a template and created a new document library from this template, as seen in the screenshot bellow after adding an item to the new list, you can see that the event occurred twice:

image

And for those of you who are sceptic the following screenshot form SharePoint Manager 2007 will prove that I am not bluffing you…

image

Now that we are aware of the problem, how do we fix it?

So I wrote a new function named RemoveDuplicateEvents to remove the duplicate events:

/// <summary>
/// This function remove duplicate events that were created when
/// saving a list with an event receiver as a template and creating
/// instances from the template
/// </summary>
/// <param name="list">The list to check for duplicate events</param>
/// <param name="className">The class which contains the receiver function</param>
/// <param name="eventType">The event type (if more than one event reciver in class)</param>
/// <returns>True if duplicate events were found, False otherwise</returns>
private bool RemoveDuplicateEvents(SPList list, string className, SPEventReceiverType eventType)
{
    //List of pointers to the duplicate events
    List<int> evnetReciverPointers = new List<int>();
    bool rc = false;
    try
    {
        SPSecurity.RunWithElevatedPrivileges(delegate
        {
            if (list.EventReceivers.Count < 2)
            {
                rc = false;
                return;
            }
            //Find events from the same type and classs
            for (int i = 0; i < list.EventReceivers.Count; i++)
            {
                if ((list.EventReceivers[i].Class == className) && (list.EventReceivers[i].Type == eventType))
                {
                    evnetReciverPointers.Add(i);
                }
            }
            //We delete one at a time
            if (evnetReciverPointers.Count > 1)
            {
                list.EventReceivers[evnetReciverPointers[1]].Delete();
                list.Update();
                rc = true;
            }
        });
 
    }
    catch (Exception ex)
    {
        //Do some error handling
    }
    return rc;
}

If we want to call this function from the event receiver we need to be aware of two things:

  1. If the problematic list was saved as a template, and we create a list instance from this template there will be 3 event handlers (and so on… save as template… instance… 4 event receivers… and so on…)
  2. Let’s say that we have a list with duplicate ItemAdded event, if in the first call to the ItemAdded function even if we remove the duplication, all the duplicate events will pop for the item who triggered the event(the next one will work fine).

that’s why in the function above I delete one duplication at a time. In order to overcome these problems your event receiver code should look like this:

public override void ItemAdded(SPItemEventProperties properties)
{
    try
    {
        this.DisableEventFiring();
 
        //Get the context item
        using (SPWeb contextWeb = properties.OpenWeb())
        {
            //Remove duplicate events
            if (RemoveDuplicateEvents(contextWeb.Lists[properties.ListId], this.GetType().ToString(), SPEventReceiverType.ItemAdded))
            {
                //because we want the code bellow the run only once
                return;
            }
            SPList contextList = contextWeb.Lists[properties.ListId];
            SPListItem contextItem = contextList.GetItemById(properties.ListItemId);
            //Sample update for testing
            contextItem["Title"] += "From event handler " + DateTime.Now.ToShortTimeString();
            contextItem.SystemUpdate(false);
        }
    }
    finally
    {
        this.EnableEventFiring();
    }
}

Stay tuned for more SharePoint adventures :-)

David Birin

Published 29 January 2009 04:51 PM by DavidBi
תגים:, , , ,

Comments

# Webmaster Crap » Blog Archive » SharePoint ??? Events are duplicated when using templates - David … said on 31 January, 2009 10:02 AM

Pingback from  Webmaster Crap  &raquo; Blog Archive   &raquo; SharePoint ??? Events are duplicated when using templates - David &#8230;

# Andrew Eberhard said on 15 March, 2010 11:10 PM

I have encountered this too.  I like your solution, but honestly the problem is hideously pervasive.  If your list happens to use content types and if one of those content types has an expiration policy set on it, the expiration policy handlers are duplicated too!  Incredibly inefficient.  I suppose we're not supposed to use site/list templates?  Very frustrating.  Thanks for posting this though.

Leave a Comment

(required) 
(required) 
(optional)
(required) 

Enter the numbers above: