What are they?
SharePoint 2007 Event Receivers are a type of feature which listens for certain events on a site, list or list item. Event Receivers are the MOSS version of document event handlers (also known as Event Sink) in SharePoint V2 technologies (WSS and SPS). Previously the document event handlers were only available for document libaries. Event receivers are now available for any type of list.
What can they be used for?
SharePoint 2007 Event Receivers add behaviours to lists or list items. They are commonly used to perform data validation (beyond SharePoint standard capabilities), to ensure data integrity or to perform a business process.
Definition
Event Receivers have before and after events.
The events relating to a site are:
-
Before
-
SiteDeleting
-
WebDeleting
-
WebMoving
-
After
-
SiteDeleted
-
WebDeleted
-
WebMoved
A class needs to inherit from SPWebEventReceiver. The behaviour is defined by overriding a method for one of the above before or after events. You can access properties that relates to the event that the feature is listening using SPWebEventProperties.
The events relating to a list are:
- Before
- FieldAdding
- FieldUpdating
- FieldDeleting
- After
- FieldAdded
- FieldUpdated
- FieldDeleted
A class needs to inherit from SPListEventReceiver. You define the behaviour by overriding a method for one of the above before or after events. You can access the event properties using the parameter SPListEventProperties.
The events releating to list items are:
- Before
- ItemAdding
- ItemUpdating
- ItemDeleting
- After
- ItemAdded
- ItemUpdated
- ItemDeleted
- ItemAttachmentAdded
- ItemAttachmentDeleted
- ItemCheckedIn
- ItemCheckedOut
- ItemFileConverted
- ItemFileMoved
- ItemUncheckedOut
A class needs to inherit from SPItemEventReceiver. You then override a method for one of the above before or after events. The event properties can be accessed by the local parameter SPItemEventProperties. One of these is the list item. For example:
public override void ItemAdded(SPItemEventProperties properties)
{
SPListItem currentListItem = properties.ListItem;
// other implementation here .....
}
Other important information of the properties object is the AfterProperties and BeforeProperties. AfterProperties provide access to the modified properties. BeforeProperties provide access to the column data before it was changed. This enables you to perform changed based validation.
How are they assigned to a list?
Event Receivers can be bound by using the ListTemplateId specified in the feature or added to the EventReceivers Collection of a list. If you are using the latter this is usually performed using a SPFeatureReceiver. A Feature Receiver allows some custom code to be executed once the feature has been installed, activated, deactivating and uninstalling (note the first two are after events and the last two are before events). The code for adding an Event Receiver to a list is:
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPWeb web = properties.Feature.Parent as SPWeb;
web.Lists["Rating History"].EventReceivers.Add(
SPEventReceiverType.ItemAdded,
"Dhunter.SharePoint.Eventhandlers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0a26195ff03df1fd",
"Dhunter.SharePoint.Eventhandlers.RatingSummaryEventHandler");
}
As you can see above, the Add method takes in the 4 part string that correctly identifies the assembly and class for the event handler.
How are events registered with the event receiver?
Events that the Event Receiver responds to are subscribed to using the feature file. For example:
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Receivers ListTemplateId="100">
<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>
</Receivers>
</Elements>
Or if the event receiver is bound to the list by code, you specify this when adding the event handler using the enumeration SPEventReceiverType. You add the event receiver to the EventReceivers collection once for every SPEventReciverType.
For example the code below adds the event handler for the ItemAdded and ItemUpdated events.
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPWeb web = properties.Feature.Parent as SPWeb;
web.Lists["Rating History"].EventReceivers.Add(
SPEventReceiverType.ItemAdded,
"Dhunter.SharePoint.Eventhandlers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0a26195ff03df1fd",
"Dhunter.SharePoint.Eventhandlers.RatingSummaryEventHandler");
web.Lists["Rating History"].EventReceivers.Add(
SPEventReceiverType.ItemUpdated,
"Dhunter.SharePoint.Eventhandlers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0a26195ff03df1fd",
"Dhunter.SharePoint.Eventhandlers.RatingSummaryEventHandler");
}
Using Before Events
It's possible to cancel the task executed using a before event. You may need to implement this behaviour because you dont want users to modify a schema of a list or that certain criteria failed when a new item has been entered. For example:
properties.ErrorMessage = "Only Administrators are allowed to modify the definiton of this list";
properties.Cancel = true;
Before events are often referred to as synchronous events. Synchronous events stop the current flow of execution until the code processed in the method for the event handler has run. These are typically used to perform validation on the entered data to maintain data integrity or provide custom validation rules that the front-end cant provide.
Using After Events
After events are asynchronous events. This doesn't stop the execution of the current flow. These are typically used to kick off a business process.
How are they bound to a content type?
In the content type definition file you need to add a XmlDocuments element that contains a XMLDocument followed by spe:Receivers and Receiver elements. For example:
<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>
What sequence numbers?
Sequence numbers apply the order that the event handlers should be executed. Take this example ... You have a list which has multiple event handlers bound (Event handler 1 and Event handler 2). Both event handlers are registered to the ItemAdded event. Event handler 1 has a sequence number of 900 and Event handler 2 has a sequence number of 1000. This means Event handler 1 will be executed first and then followed by Event handler 2.
Deployment considerations
The compiled class file must be strongly named and deployed to the GAC (Global Assembly Cache).
If you bind the event receiver using a feature file it can only be scoped at the site level. It cannot be bound to an instance of a list or to a content type.
Points to note
Disable Event Firing.
If you modify the current SPList for a List Event Receiver or SPListItem for an Item Event Receiver you must call DisableEventFiring() before commiting the change. This stops recursive event firing and the possiblity of entering an infinite loop. After you have committed the change, you should then call EnableEventFiring() to return the processing to its normal behaviour.
Performance
What effect would bulk creation or upload of items have on the perfromance of our system? You should bear this in mind when designing, developing and testing the system. Intensive calls during event handlers will hinder the performance of the system, especially with synchronous events as the flow of execution is stopped until the code within the event handler is executed.