SharePoint gives provision to developers for executing their custom code on many SharePoint actions/
events, e.g. feature activation/ deactivations, List item addition/ deletion etc.
These are called as Event Receivers in SharePoint terminology.
Though it seems easy, I feel Event receivers are one of the most complex
SharePoint artifacts to understand especially Event Host types. Hence I decided to
do some tutorials. This post talks about my findings as well as some basics.
Following SharePoint 2010 artifacts supports event receivers.
- Site collection
- Sub-site
- Feature
- List
- List site column
- List Item
- Workflow
Site Collection (SPSite) Events:
Event Method
|
Receiver base class
|
When
|
Nature
|
SiteDeleting
|
SPWebEventReceiver
|
Occurs when a site collection is being deleted.
|
Synchronous
|
SiteDeleted
|
SPWebEventReceiver
|
Occurs after a site collection has been deleted.
|
Synchronous/ Asynchronous
|
Subsite (SPWeb) Events :
Event Method
|
Receiver base class
|
When
|
Nature
|
WebAdding
|
SPWebEventReceiver
|
Occurs before a new subsite is created
|
Synchronous
|
WebProvisioned
|
SPWebEventReceiver
|
Fires after a subsite is fully provisioned and the provisioning process has stopped
|
Synchronous/ Asynchronous
|
WebDeleting
|
SPWebEventReceiver
|
Occurs before an existing Web site is completely deleted.
|
Synchronous
|
WebDeleted
|
SPWebEventReceiver
|
Occurs after an existing Web site is completely deleted.
|
Synchronous/ Asynchronous
|
WebMoving
|
SPWebEventReceiver
|
Occurs before an existing Web site has been
renamed or moved to a different
parent object
|
Synchronous
|
WebMoved
|
SPWebEventReceiver
|
Occurs after an existing Web site has been moved.
|
Synchronous/ Asynchronous
|
Notes:
- The Sub Site event receiver does not execute on root web site of the site collection.
- Event can be hosted by either individual subsite or whole site collection. It is controlled by scope of the feature who is registering the event and Scope attribute of the Receivers element.
List (SPList) Events:
Event Method
|
Receiver base class
|
When
|
Nature
|
ListAdding
|
SPListEventReceiver
|
Occurs before a list is created on a website
|
Synchronous
|
ListAdded
|
SPListEventReceiver
|
Raised after a list is added to a website
|
Synchronous/ Asynchronous
|
ListDeleting
|
SPListEventReceiver
|
Raised before a list is deleted.
|
Synchronous
|
ListDeleted
|
SPListEventReceiver
|
Occurs after a list is deleted.
|
Synchronous/ Asynchronous
|
EmailReceived
|
SPEmailEventReceiver
|
Provides a method for trapping the event when a list receives an e-mail message
|
Synchronous/ Asynchronous
|
Notes:
Event can be hosted by either individual subsite or whole site collection. It is
controlled by scope of the feature who is registering the event and
Scope attribute of the Receivers element. Please see the figure 1.
List Field (SPField) Events:
Event Method
|
Receiver base class
|
When
|
Nature
|
FieldAdding
|
SPListEventReceiver
|
Occurs before a field link is added to a content type, or field is added to a list.
|
Synchronous
|
FieldAdded
|
SPListEventReceiver
|
Occurs after a field link is added or after field is added to a list.
|
Synchronous/ Asynchronous
|
FieldDeleting
|
SPListEventReceiver
|
Occurs before a field is removed from the list
|
Synchronous
|
FieldDeleted
|
SPListEventReceiver
|
Occurs after a field link has been removed from the content type or field has been
removed from the list
|
Synchronous/ Asynchronous
|
FieldUpdating
|
SPListEventReceiver
|
Occurs before a field link is updated or field is updated in list
|
Synchronous
|
FieldUpdated
|
SPListEventReceiver
|
Occurs after a field link has been updated or field is updated in list
|
Synchronous/ Asynchronous
|
List Item (SPListItem) Events:
Event Method
|
Receiver base class
|
When
|
Nature
|
ItemAdding
|
SPItemEventReceiver
|
Occurs before an item is added
|
Synchronous
|
ItemAdded
|
SPItemEventReceiver
|
Occurs after an item is added
|
Synchronous/
Asynchronous
|
ItemDeleting
|
SPItemEventReceiver
|
Occurs before an item is deleted
|
Synchronous
|
ItemDeleted
|
SPItemEventReceiver
|
Occurs after an item is deleted
|
Asynchronous
|
ItemUpdating
|
SPItemEventReceiver
|
Occurs before an item is changed
|
Synchronous
|
ItemUpdated
|
SPItemEventReceiver
|
Occurs after an item is changed
|
Synchronous/ Asynchronous
|
ItemFileConverted
|
SPItemEventReceiver
|
Occurs after a file in a document library is converted from one type to another
|
Synchronous/ Asynchronous
|
ItemFileMoving
|
SPItemEventReceiver
|
Occurs before a file is moved
|
Synchronous
|
ItemFileMoved
|
SPItemEventReceiver
|
Occurs after a file is moved
|
Synchronous/ Asynchronous
|
ItemCheckingIn
|
SPItemEventReceiver
|
Occurs before an item is checked in
|
Synchronous
|
ItemCheckedIn
|
SPItemEventReceiver
|
Occurs after an item is checked in
|
Synchronous/ Asynchronous
|
ItemCheckingOut
|
SPItemEventReceiver
|
Occurs before an item is checked out
|
Synchronous
|
ItemCheckedOut
|
SPItemEventReceiver
|
Occurs after an item is checked out
|
Synchronous/ Asynchronous
|
ItemAttachmentAdding
|
SPItemEventReceiver
|
Occurs before an attachment is added to an item
|
Synchronous
|
ItemAttachmentAdded
|
SPItemEventReceiver
|
Occurs after an attachment is added to an item
|
Synchronous/ Asynchronous
|
ItemAttachmentDeleting
|
SPItemEventReceiver
|
Occurs before an attachment is removed from an item
|
Synchronous
|
ItemAttachmentDeleted
|
SPItemEventReceiver
|
Occurs after an attachment is removed from an item
|
Synchronous/ Asynchronous
|
Workflow Events:
Event Method
|
Receiver base class
|
When
|
Nature
|
WorkflowStarting
|
SPWorkflowEventReceiver
|
Occurs before a workflow is created
|
Synchronous
|
WorkflowStarted
|
SPWorkflowEventReceiver
|
Fires once workflow is started
|
Synchronous/ Asynchronous
|
WorkflowPostponed
|
SPWorkflowEventReceiver
|
Raised when the workflow is postponed, which happens the farm is too busy handling
other workflows.
|
Synchronous/ Asynchronous
|
WorkflowCompleted
|
SPWorkflowEventReceiver
|
Occurs after an existing Web site is completely deleted.
|
Synchronous/ Asynchronous
|
Important Notes for List, List field, list
item and workflow events:
- Event can be hosted by Site Collection, individual subsite, List templates, List instances, Content Type. It is controlled by scope of the feature who is registering the event and Scope attribute of the Receivers element. Please see the figure 1.
- Event can be registered to the list using
<Receivers>
tag by two ways.
- Attaching to the list template using <Receivers ListTemplateId="" >
- Attaching to the list instance using <Receivers ListUrl="" >
- Events can be registered to the content type by copying the Receiver tag into the XmlDocuments tag. Event receivers can be registered to both site content type (element.xml) or list content type (list schema.xml)
Feature Events:
Event Method
|
Receiver base class
|
When
|
Nature
|
FeatureActivated
|
SPFeatureReceiver
|
Raised after a feature has been activated
|
Asynchronous
|
FeatureDeactivating
|
SPFeatureReceiver
|
Raised before a feature is deactivated
|
Synchronous
|
FeatureInstalled
|
SPFeatureReceiver
|
Raised after a feature has been installed
|
Asynchronous
|
FeatureUninstalling
|
SPFeatureReceiver
|
Raised before a feature is uninstalled
|
Synchronous
|
FeatureUpgrading
|
SPFeatureReceiver
|
Raised when a feature is upgrading
|
Synchronous
|
Notes:
Nothing explains Feature Upgrade event receiver better than Chris O’Brien’s post
http://www.sharepointnutsandbolts.com/2010/06/feature-upgrade-part-1-fundamentals.html.
Ways to Attach Event Receivers:
- Declarative Way (element.xml)
In this approach, event receivers are registered using element manifest files. This approach works in Sandbox solution as well. - Programmatic way
In this way, event receivers are created programmatically, ideally in feature receiver code.
You can download my tutorial having many examples of all kind of event receivers with different host types here.
Below, I have explained the tutorial code with help of screenshots taken using
SharePoint Manager 2010. For testing purposes, I created a Site Collection named as SharePoint Custom Development and a sub-site named as SubSite.
1. SPSiteEventReceivers
Shows how to create site collection event receivers.
<!--The Project item should be associated with a feature scoped at site collection.-->
<Receivers >
<Receiver>
<Name>SPSiteEventReceiversSiteDeleting</Name>
<Type>SiteDeleting</Type>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>EventReceivers.SPSiteEventReceivers.SPSiteEventReceivers</Class>
<SequenceNumber>10000</SequenceNumber>
</Receiver>
<Receiver>
<Name>SPSiteEventReceiversSiteDeleted</Name>
<Type>SiteDeleted</Type>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>EventReceivers.SPSiteEventReceivers.SPSiteEventReceivers</Class>
<SequenceNumber>10000</SequenceNumber>
</Receiver>
</Receivers>
|
2.
SiteCollectionScopedSPWebEventReceivers:
These are the sub-site event receivers hosted by site collection.
<!-- The parent feature scope is 'Site'. The host of these events will be site collection due to
Receivers tag Scope='Site' attribute.
Hence these events will be bound to every subsite within the site collection except RootWeb-->
<Receivers Scope="Site" >
<Receiver>
<Name>SiteCollectionScopedSPWebEventReceiversWebDeleting</Name>
<Type>WebDeleting</Type>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>EventReceivers.SiteCollectionScopedSPWebEventReceivers.SiteCollectionScopedSPWebEventReceivers</Class>
<SequenceNumber>10000</SequenceNumber>
</Receiver>
<Receiver>
<Name>SiteCollectionScopedSPWebEventReceiversWebMoving</Name>
<Type>WebMoving</Type>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>EventReceivers.SiteCollectionScopedSPWebEventReceivers.SiteCollectionScopedSPWebEventReceivers</Class>
<SequenceNumber>10000</SequenceNumber>
</Receiver>
<Receiver>
<Name>SiteCollectionScopedSPWebEventReceiversWebAdding</Name>
<Type>WebAdding</Type>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>EventReceivers.SiteCollectionScopedSPWebEventReceivers.SiteCollectionScopedSPWebEventReceivers</Class>
<SequenceNumber>10000</SequenceNumber>
</Receiver>
</Receivers>
|
- Host type of both above event receivers is Site Collection. Hence when seen in the Event Receiver collection of Site collection, it look like this.
3.
IndividualSubSiteSPWebEventReceivers
These sub site event receivers are hosted by individual sub site.
<!--
These events will be bound to the subsites in which parent feature is activated because.
1. The parent feature scope is 'Web'.
2. Scope='Web' attribute of Receivers tag.
-->
<Receivers Scope="Web" >
<Receiver>
<Name>IndividualSubSiteSPWebEventReceiversWebDeleted</Name>
<Type>WebDeleted</Type>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>EventReceivers.IndividualSubSiteSPWebEventReceivers.IndividualSubSiteSPWebEventReceivers</Class>
<SequenceNumber>10000</SequenceNumber>
</Receiver>
<Receiver>
<Name>IndividualSubSiteSPWebEventReceiversWebMoved</Name>
<Type>WebMoved</Type>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>EventReceivers.IndividualSubSiteSPWebEventReceivers.IndividualSubSiteSPWebEventReceivers</Class>
<SequenceNumber>10000</SequenceNumber>
</Receiver>
<Receiver>
<Name>IndividualSubSiteSPWebEventReceiversWebProvisioned</Name>
<Type>WebProvisioned</Type>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>EventReceivers.IndividualSubSiteSPWebEventReceivers.IndividualSubSiteSPWebEventReceivers</Class>
<SequenceNumber>10000</SequenceNumber>
</Receiver>
</Receivers>
|
4.
ListTemplateEventReceiver
- This event receiver is associated with Announcement List Template. All list created through Announcement list template will have this event receiver attached.
<!-- ListTemplateId attribute is used to attach the ItemAdded event to Announcement list template.
As the parent feature scope 'Web', the host type of this event will be individual subsite in which
parent feature is activated.
-->
<Receivers ListTemplateId="104">
<Receiver>
<Name>ListTemplateEventReceiverItemAdded</Name>
<Type>ItemAdded</Type>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>EventReceivers.ListTemplateEventReceiver.ListTemplateEventReceiver</Class>
<SequenceNumber>10000</SequenceNumber>
</Receiver>
</Receivers>
|
5.
IndividualListEventReceiver
This event receiver is attached to the Test Events List created declaratively.
<!--ListUrl attribute is used to attach the ItemAdded event to "Test Events List" list created in this project.-->
<Receivers ListUrl="Lists/Test Events List">
<Receiver>
<Name>IndividualListEventReceiverItemAdded</Name>
<Type>ItemAdded</Type>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>EventReceivers.IndividualListEventReceiver.IndividualListEventReceiver</Class>
<SequenceNumber>10000</SequenceNumber>
</Receiver>
</Receivers>
|
6.
ContentTypeEventReceiver
This shows how to associate event receiver to a content type.
<!-- Parent ContentType: Announcement (0x0104). Note that without "Inherits='false'",
event receiver
does not get attached to the content type. This is due to a known bug in SharePoint
2010. -->
<ContentType ID="0x010400069AB2346B6241699E565C8E004F2F4E"
Name="Custom Announcement"
Group="Custom Content Types"
Description="This CT is created to demonstrate the
association of event receivers."
Inherits="false"
Overwrite="TRUE"
Version="0">
<FieldRefs>
<FieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}"
Name="Title"/>
</FieldRefs>
<XmlDocuments>
<XmlDocument
NamespaceURI="http://schemas.microsoft.com/sharepoint/events">
<Receivers xmlns:spe="http://schemas.microsoft.com/sharepoint/events">
<Receiver>
<Name>ContentTypeEventReceiver</Name>
<Type>ItemAdded</Type>
<SequenceNumber>10000</SequenceNumber>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>$SharePoint.Type.a3dac829-4c36-46a9-930c-55698372b050.FullName$</Class>
<Data></Data>
<Filter></Filter>
</Receiver>
</Receivers>
</XmlDocument>
</XmlDocuments>
</ContentType>
|
7.
WorkflowEventReceivers
- This example shows how to attach the workflow event receivers to list template and individual list.
<!--Workflow events will
be attached to the Links list template.
VS 2010 asks for
selecting the list template id by default.
But by changing
the ListUrl attribute, events can be attached to individual list too.
-->
<Receivers ListTemplateId="103">
<Receiver>
<Name>WorkflowEventReceiversWorkflowStarting</Name>
<Type>WorkflowStarting</Type>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>EventReceivers.WorkflowEventReceivers.WorkflowEventReceivers</Class>
<SequenceNumber>10000</SequenceNumber>
</Receiver>
</Receivers>
<Receivers ListUrl="Lists/Links">
<Receiver>
<Name>WorkflowEventReceiversWorkflowCompleted</Name>
<Type>WorkflowCompleted</Type>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>EventReceivers.WorkflowEventReceivers.WorkflowEventReceivers</Class>
<SequenceNumber>10000</SequenceNumber>
</Receiver>
</Receivers>
|
8. Programmatically creating Event receivers :
The below code shows how to register/ remove the event receiver through feature
receiver .
public class
EventReceiverAssociatorEventReceiver : SPFeatureReceiver
{
public override
void FeatureActivated(SPFeatureReceiverProperties
properties)
{
SPWeb web = properties.Feature.Parent as
SPWeb;
if (web != null)
{
SPList list = web.Lists.TryGetList("Object Model Event Receivers");
if (list == null)
{
Guid listGUID = web.Lists.Add("Object
Model Event Receivers",
"Created for testing programmatic association of
event receivers.",
SPListTemplateType.GenericList);
list = web.Lists[listGUID];
}
AddEventReceiverToList("EventReceivers.ProgrammaticallyAddedEventReceiver.ProgrammaticallyAddedEventReceiver",
list,
"EventReceivers, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=f3155a6cff2154bb",
SPEventReceiverType.ItemAdded,
SPEventReceiverSynchronization.Asynchronous);
}
}
public
override void
FeatureDeactivating(SPFeatureReceiverProperties
properties)
{
SPWeb web = properties.Feature.Parent as
SPWeb;
if (web != null)
{
SPList list = web.Lists.TryGetList("Object Model Event Receivers");
if (list != null)
{
foreach (SPEventReceiverDefinition
eventreceiverDef in list.EventReceivers)
{
if (eventreceiverDef.Assembly ==
"EventReceivers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f3155a6cff2154bb"
&& eventreceiverDef.Type == SPEventReceiverType.ItemAdded)
{
eventreceiverDef.Delete();
break;
}
}
}
}
}
protected
static void
AddEventReceiverToList(string className, SPList list, string
assemblyName, SPEventReceiverType eventReceiverType,
SPEventReceiverSynchronization eventReceiverSynchronization)
{
if (className == null)
throw new ArgumentNullException("Class name cannot be null.");
if (list == null)
throw new ArgumentNullException("List cannot be null.");
if (assemblyName == null)
throw new ArgumentNullException("Assembly name cannot be null.");
SPEventReceiverDefinition eventReceiver = list.EventReceivers.Add();
eventReceiver.Class
= className;
eventReceiver.Assembly
= assemblyName;
eventReceiver.Type
= eventReceiverType;
eventReceiver.Synchronization
= eventReceiverSynchronization;
eventReceiver.Update();
}
}
|
Updated (11/7/2012):
While
using BIN deployment in one of my projects, I observed that the feature with
event receivers throws File Not Found error and does not get activated. After
googling, I came to know that this behavior is by design. SharePoint 2010 does
not support Event receivers. I also observed that event receiver feature gets
activated when I added Unrestricted="true" to the NamedPermissionSet into
the custom CAS Policy config file present in the SharePointRoot\CONFIG folder. Unfortunately
this change is not recommended due to security reasons. So only way to fix this is to change the Deployment target to GAC instead of BIN.
|
Few Key take ways and findings:
- Feature scope plays role in deciding the event receiver host object
- Host type also can be controlled through Receivers tag Scope attribute .
- Sandbox solution does not allow event receivers to be attached programmatically.
- Declaratively event receivers can be attached to individual list using ListUrl attribute of Receivers tag.