Event Receivers


Table of Contents

Event Receivers are triggered by certain events on either a SPWeb, SPList or SPListItem. Event Receivers can be attached by either using feature elements definitions or by using the object model (using Feature Receivers). The event handler method that are attached are defined in a separate class Event Receiver class that implements either SPWebEventReceiver, SPListEventReceiver, SPItemEventReceiver or SPEmailEventReceiver.

SPWebEventReceiver

   
Before
  • SiteDeleting
  • WebDeleting
  • WebMoving
After
  • SiteDeleted
  • WebDeleted
  • WebMoved

SPListEventReceiver

   
Before
  • FieldAdding
  • FieldUpdating
  • FieldDeleting
After
  • FieldAdded
  • FieldUpdated
  • FieldDeleted

SPItemEventReceiver

   
Before
  • ItemAdding
  • ItemUpdating
  • ItemDeleting
After
  • ItemAdded
  • ItemUpdated
  • ItemDeleted
  • ItemAttachmentAdded
  • ItemAttachmentDeleted
  • ItemCheckedIn
  • ItemCheckedOut
  • ItemFileConverted
  • ItemFileMoved
  • ItemUncheckedOut

SPEmailEventReceiver

   
After
  • EmailReceived

Creating an Event Receiver class

The following code is recommended as a base for Event Receivers to ensure a few things:

  • you don't get the method firing more than once with the use of the DisableEventFiring
  • you log the exception so you get visibility of the events as they are run (I would recommend logging the exception better with Stack Trace, but put that there just to show. See SharePoint Logging for more details)
  • you log enter and exiting the method to make sure it's actually being called (remember you need to add an event receiver for each method - see below)
public class ScheduleListEventReceiver : SPItemEventReceiver
{
  public override void ItemAdding(SPItemEventProperties properties)
  {
    System.Diagnostics.Debug.WriteLine("ScheduleListEventReceiver.ItemAdding(): begin");
    try
    {
      this.DisableEventFiring();
      //TODO: do stuff!
      base.ItemAdding(properties);
    }
    catch (Exception ex)
    {
       System.Diagnostics.Debug.WriteLine("ScheduleListEventReceiver.ItemAdded() exception" + ex.ToString());

    }
    finally
    {
       this.EnableEventFiring();
    }
    System.Diagnostics.Debug.WriteLine("ScheduleListEventReceiver.ItemAdding(): end");
  }

  public override void ItemAdded(SPItemEventProperties properties)
  {
    System.Diagnostics.Debug.WriteLine("ScheduleListEventReceiver.ItemAdded(): begin");
    try
    {
      this.DisableEventFiring();
      //TODO: do stuff!
      base.ItemAdded(properties);
    }
    catch (Exception ex)
    {
       System.Diagnostics.Debug.WriteLine("ScheduleListEventReceiver.ItemAdded() exception" + ex.ToString());
    }
    finally
    {
       this.EnableEventFiring();
    }
    System.Diagnostics.Debug.WriteLine("ScheduleListEventReceiver.ItemAdded(): end");
  }

  public override void ItemUpdating(SPItemEventProperties properties)
  {
    System.Diagnostics.Debug.WriteLine("ScheduleListEventReceiver.ItemUpdating(): begin");
    try
    {
      this.DisableEventFiring();
      //TODO: do stuff!
      base.ItemUpdating(properties);
    }
    catch (Exception ex)
    {
       System.Diagnostics.Debug.WriteLine("ScheduleListEventReceiver.ItemUpdating() exception" + ex.ToString());
    }
    finally
    {
       this.EnableEventFiring();
    }
    System.Diagnostics.Debug.WriteLine("ScheduleListEventReceiver.ItemUpdating(): end");
  }

  public override void ItemUpdated(SPItemEventProperties properties)
  {
    System.Diagnostics.Debug.WriteLine("ScheduleListEventReceiver.ItemUpdated(): begin");
    try
    {
      this.DisableEventFiring();
      //TODO: do stuff!
      base.ItemUpdated(properties);
    }
    catch (Exception ex)
    {
       System.Diagnostics.Debug.WriteLine("ScheduleListEventReceiver.ItemUpdated() exception" + ex.ToString());
    }
    finally
    {
       this.EnableEventFiring();
    }
    System.Diagnostics.Debug.WriteLine("ScheduleListEventReceiver.ItemUpdated(): end");
  }
}

Updating item properties in Event Receiver

This one burnt up hours of my time...on the properties (SPItemEventProperties) parameter passed in there are various objects inside it. The misleading on is the .ListItem one. If you want to change a property on the ListItem please be aware that you need to use the .AfterProperties and then let the base method call actually do the update. If you try and call properties.ListItem.Update() within your event receiver you will receive errors such as Save Conflicts.

Cancelling Events

You can cancel event receivers which will provide a generic SharePoint error page using the following code. This is often used as a serverside way of validating submissions.

01: properties.ErrorMessage = "You cannot save this list item at this time";
02: properties.Cancel = true;

Using feature manifest to attach Event Receiver to List

Deployment scope: Feature applies to Web (web site).

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Receivers ListTemplateId="100">
    <Receiver>
      <Name>ScheduleListEventReceiver</Name>
      <Type>ItemAdded</Type>
      <SequenceNumber>10000</SequenceNumber>
      <Assembly>jeremythake.tvshowschedulesite, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8eb9a930004f2f1a</Assembly>
      <Class>jeremythake.tvshowschedulesite.ScheduleListEventReceiver</Class>
      <Data></Data>
      <Filter></Filter>
    </Receiver>
    <Receiver>
      <Name>ScheduleListEventReceiver</Name>
      <Type>ItemUpdated</Type>
      <SequenceNumber>10000</SequenceNumber>
      <Assembly>jeremythake.tvshowschedulesite, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8eb9a930004f2f1a</Assembly>
      <Class>jeremythake.tvshowschedulesite.ScheduleListEventReceiver</Class>
      <Data></Data>
      <Filter></Filter>
    </Receiver>
  </Receivers>
</Elements>

Using object model to attach Event Receiver to List

Deployment scope: Programmatically applied per list.

01: web.Lists["Schedule"].EventReceivers.Add(
02:  SPEventReceiverType.ItemAdded,
03:  "jeremythake.tvshowschedulesite, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8eb9a930004f2f1a",
04:  "jeremythake.tvshowschedulesite.ScheduleListEventReceiver");
05: web.Lists["Schedule"].EventReceivers.Add(
06:  SPEventReceiverType.ItemUpdated,
07:  "jeremythake.tvshowschedulesite, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8eb9a930004f2f1a",
08:  "jeremythake.tvshowschedulesite.ScheduleListEventReceiver");

Can also be done a little bit more programmatically

Assembly assembly = Assembly.GetExecutingAssembly();
SPEventReceiverDefinition eventReceiver = list.EventReceivers.Add();
eventReceiver.Name = "Policy of Truth";
eventReceiver.Type = SPEventReceiverType.ItemUpdated;
eventReceiver.SequenceNumber = 200;
eventReceiver.Assembly = assembly.FullName;
eventReceiver.Class = "TST.POC.PolicyFeatures.PolicyOfTruthHandler";
eventReceiver.Update();

Source: Tom Stegeman

Using Content Types to attach Event Receiver to Lists

Deployment scope: Content type feature applies to Site (site collection).

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <ContentType ID="CONTENT TYPE ID" Name="CONTENT TYPE NAME" Group="Custom"
               Description="CONTENT TYPE DESCRIPTION" Version="0">
    <FieldRefs>
      <FieldRef ID="FIELD ID" Name="FIELD NAME" />
    </FieldRefs>
    <XmlDocuments>
      <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/events">
        <spe:Receivers xmlns:spe="http://schemas.microsoft.com/sharepoint/events">
          <Receiver>
            <Name>RatingSummaryEventHandler</Name>
            <Type>ItemAdded</Type>
            <SequenceNumber>10000</SequenceNumber>
            <Assembly>Dhunter.SharePoint.Eventhandlers, Version=1.0.0.0, Culture=neutral,
                      PublicKeyToken=0a26195ff03df1fd</Assembly>
            <Class>Dhunter.SharePoint.Eventhandlers.RatingSummaryEventHandler</Class>
            <Data></Data>
            <Filter></Filter>
          </Receiver>
          <Receiver>
            <Name>RatingSummaryEventHandler</Name>
            <Type>ItemUpdated</Type>
            <SequenceNumber>10000</SequenceNumber>
            <Assembly>Dhunter.SharePoint.Eventhandlers, Version=1.0.0.0, Culture=neutral,
                      PublicKeyToken=0a26195ff03df1fd</Assembly>
            <Class>Dhunter.SharePoint.Eventhandlers.RatingSummaryEventHandler</Class>
            <Data></Data>
            <Filter></Filter>
          </Receiver>
        </spe:Receivers>
      </XmlDocument>
    </XmlDocuments>
  </ContentType>
</Elements>

Source: Dave Hunter

Gotchas

BeforeProperties and AfterProperties

When user needs to access the data associated with event receivers, they access it using event receiver properties. The SPItemEventProperties contains the after and before property of an item which can be used to access the item value before/after the change occurred. The event receiver property also contains an important field called ReceiverData which can be used to store the custom data. This data can be used to pass any information which is not present in the properties itself.
The table below shows the values contained in the SPItemEventProperties properties when the specific event occurs for the list:

List properties.ListItem (Before property value) Properties.afterProperties
ItemAdding Null New Value
ItemAdded New Value New Value
ItemUpdating Old Value New Value
ItemUpdated New Value New Value
ItemDeleting Old Value Null
ItemDeleted Null Null

Source: Bamboo

Add for each ItemAdded, ItemUpdated etc. event not just once for the list

When you are adding Event Receivers you need to remember that you have to add a EventRecevier for each SPEventReceiverType e.g. ItemAdded or ItemUpdated.

Office 2007 documents

Office 2007 documents cannot be modified in the ItemAdding Event (using AfterProperties) unless SPWeb.ParserEnabled = false.

Debugging

Debugging an SPEmailEventReceiver requires attaching the debugger to the OWSTIMER.EXE process. This is because the timer service fires the Incoming E-mail timer job, rather than the SharePoint web application.

ItemUpdating & ItemUpdated running twice

Source: chakkaradeep
The ItemUpdating event or the ItemUpdated event occurs two times when you enable the Require Check Out option for Document Library. This will also cause custom event code to run twice.

Here is the solution from Microsoft:

To work around this behavior, examine the vti_sourcecontrolcheckedoutby property inside an event receiver. If the vti_sourcecontrolcheckedoutby property exits in the BeforeProperties property but not in the AfterProperties property, the event was caused by checking in a document. The following sample code shows you how to do this.

if (properties.AfterProperties["vti_sourcecontrolcheckedoutby"] == null &&

    properties.BeforeProperties["vti_sourcecontrolcheckedoutby"] != null)
{
           //This is when the update event is triggered by check-in.
}
else
{
          //This is triggered by events other than check-in action.
}

ItemAdding AfterProperties

Thanks to Adam Toth for pointing out that you need to use the Display Name of a Site Column and not the Internal Name on AfterProperties.
For example use:

properties.AfterProperties["Container Record Number"] = "blah";
base.ItemAdding(properties);

Not this:

properties.AfterProperties["Container_x0020_Record_x0020_Number"] = "blah";
base.ItemAdding(properties);

Event Receivers on Content Types

Source: Steven Van de Craen

  • All ItemAdding events trigger in case of file upload via WebDAV or the Upload page
  • Copying a file triggers the ItemAdding and ItemUpdating events, but not the ItemAdded event
  • Restoring from the Recycle Bin triggers all ItemAdding and ItemAdded events regardless of Content Type
  • Restoring a previous version is seen as an update (makes sense)

ItemDeleted missing vital information about

Source: Einar Otto Stangvik
While ItemDeleted is indeed signaled for list item deletions, it holds next to no usable information about which item was actually deleted. BeforeProperties and AfterProperties are both null, the deleted element's title is missing and no other reference back to the deleted item can be found. See the above post for workaround discussion.

External Links

Labels

splist splist Delete
spitemeventreceiver spitemeventreceiver Delete
eventreceiver eventreceiver Delete
spwebeventreceiver spwebeventreceiver Delete
spweb spweb Delete
splistitem splistitem Delete
splistitemeventreceiver splistitemeventreceiver Delete
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.


  1. May 21, 2009

    Anonymous says:

    I think there is a mistake in the introduction paragraph, in the following ...

    I think there is a mistake in the introduction paragraph, in the following phrase:

    The event handler method that are attached are defined in a separate class Event Receiver class that implements either SPWebEventReceiver, SPItemEventReceiver, SPListItemEventReceiver or SPEmailEventReceiver

    The bit in red should be SPListEventReceiver.

    1. Jun 13, 2009

      Keith Dahlby says:

      Fixed.

      Fixed.

  2. Jul 02, 2009

    Anonymous says:

    Another GOTCHA SPItemEventReceiver.BeforeProperties are only available on docum...

    Another GOTCHA

    SPItemEventReceiver.BeforeProperties are only available on document libraries and not on custom lists. See below article for more GOTCHAS.

    http://msdn.microsoft.com/en-us/library/aa979520.aspx

  3. Sep 30

    Anonymous says:

    Hi Can you please tell how to Programmatically populate the WebParts into the ...

    Hi

    Can you please tell how to Programmatically populate the WebParts into the gallery, which was previously deleted(programmatically ) from the "Webpart Gallery" list ?

    With regards
    Biju

  4. Dec 14

    Anonymous says:

    Gotcha 1 The advice in this article for using AfterProperties in ItemAdding is...

    Gotcha 1

    The advice in this article for using AfterProperties in ItemAdding is to use the Display Name of the field.

    Currently in an SP1 32bit environment this doesn't seem to ring true! AfterProperties accessed via the Display Name return null. Using the Internal Name however works and the fields can be set accordingly.

    Cotcha 2

    In the provided ScheduleListEventReceiver example the base methods are called

    e.g. base.ItemUpdating(properties).

    Calling the base methods as illustrated can cause unwanted behaviour

    i.e. calling the base method after setting 'properties.Cancel = true' seems to prevent it from cancelling

    Either forget calling the base methods alltogether, or call them first, rather than last.


Creative Commons License
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.