Why does my event receiver run multiple times?

Why does my event receiver / handler run more than once when I update or add a new list item?

There are a few common situations where this can occur. The first and most obvious is when you are handling an ItemUpdated event and within the event you  update the item in question again from your code.  Obviously, without precautions this will trigger another update! (This can happen from other events too such as ItemAdded)

The following function writes an entry to the Application event log everytime it runs. It also checks for a null title or a title that does not equal "Title Updated in ItemUpdated". If it finds either it updates the Title field of the current item.

public override void ItemUpdated(SPItemEventProperties properties)
{
    LogEvent("In ItemUpdated");
    SPListItem currentItem = properties.ListItem;
    // If title is not what we want set it
    if (currentItem["Title"] == null || currentItem["Title"].ToString().Equals("Title Updated in ItemUpdated") == false)
    {
        currentItem["Title"] = "Title Updated in ItemUpdated";
        currentItem.Update();
    }
}

FYI LogEvent() is just some simple code to log to the application event log:

private void LogEvent(String msg)
{
    SPSecurity.RunWithElevatedPrivileges(delegate()
    {
        System.Diagnostics.EventLog el = new System.Diagnostics.EventLog();
        el.Source = "DupeEventReceiver";
        el.Log = "Application";
        el.WriteEntry(msg);
    });
}

 

When I update a field in one of the listitems I see the following logged in the event log (as expected).


The reason it only runs once is because I am checking the title value before I do the update. The 2nd time around the title is the same so the Update() does not occur.

The solution to this problem is very simple: Call DisableEventFiring immediately before you modify the list item and then call EnableEventFiring when you are finished.

public override void ItemUpdated(SPItemEventProperties properties)
{
    LogEvent("In ItemUpdated");
   
    // Prevent update events from going out during the update
this.DisableEventFiring();

    SPListItem currentItem = properties.ListItem;
    // If title is not what we want set it
    if (currentItem["Title"] == null || currentItem["Title"].ToString().Equals("Title Updated in ItemUpdated") == false)
    {
        currentItem["Title"] = "Title Updated in ItemUpdated";
        currentItem.Update();
    }
    // Re-enable event firing
this.EnableEventFiring();

}

The second common scenario for your event receiver running multiple times is having the event handler registered to the same list more then once.

I've ran into this scenario before mostly in developer environments where registration is occuring in multiple ways. For example deploying your event receiver with VSEWSS and then programmatically registering it (again) in a feature receiver.

To detect whether this is going on in your environment you can write a very simple console application to enumerate through the registered receivers for your list.

private static void ListEventReceivers(String SiteName, String ListName)
{
    using (SPSite sps = new SPSite(SiteName))
    {
        using (SPWeb spw = sps.OpenWeb())
        {
            SPList splist = spw.Lists[ListName];
            foreach (SPEventReceiverDefinition sprd in splist.EventReceivers)
            {
                Console.WriteLine(sprd.Class + " " + sprd.Name);
            }
        }
    }

The output for my test environment after the vsewss/programmatic mix:

You'll notice from the output that my event receiver has multiple registrations for the ItemUpdated() event. This is because my feature receiver programmatically registered this event.. Likely, you'll only run into this scenario in developer environments where there is a lot of experimenting going on but it is a good thing to be aware of.

The output from my event receiver when updating a list item is as expected:

 

(Note I'm only calling LogEvent in ItemUpdated() not ItemUpdating())

To clean this list up you can programmatically delete the event receivers and re-register.

This example programmatically removes all event receivers from the assembly "BlogSampleDupeER.dll":

private static void UnregisterEventReceiver(String SiteName, String ListName)
{
    using (SPSite sps = new SPSite(SiteName))
    {
        using (SPWeb spw = sps.OpenWeb())
        {
            SPList splist = spw.Lists[ListName];
            List<SPEventReceiverDefinition> ersToRemove = new List<SPEventReceiverDefinition>();

            foreach (SPEventReceiverDefinition sprd in splist.EventReceivers)
            {
                if (sprd.Assembly.Contains("BlogSampleDupeER") == true)
                {

                   ersToRemove.Add(sprd);
                }
            }

            foreach (SPEventReceiverDefinition sprd in ersToRemove)
            {
                sprd.Delete();
            }
        }
    }
}

A third culprit is if you have "Require Checkout" enabled on your document library. To see a workaround for this see the following KB: https://support.microsoft.com/kb/939307

There are likely other causes for event receivers running more than once but these are the two that I run into the most while working with customers.

Hope it helps!