Creating Event receivers in SharePoint is a very common task With the new Visual Studio 2010, its more easy than before though you could do same with WSP builder in SharePoint 2007. Also the VSEWSS provided a few templates that could be used. Lets look at what has changed and what hasn’t changed in SharePoint 2010
- Fire up Visual Studio 2010 and from the templates select “Event Receiver” for the new project under SharePoint 2010 and name the project as “MyCustomEventReceiver”
- Create the Event Receiver and it would ask you for the URL of the site against which you would like to create the Event Receiver and next you would see a dialog to select various options for type of events as below
- The next set of options for the List/Library against you would like to deploy the event receiver
Damn!!! but where is the option I could select a content type so that Visual Studio takes care of registering against the list /library to which I would like to deploy that Event Receiver… I don’t want to deploy MyCustomEventReceiver against all the Calendar Lists in the Site.
I am not sure why MS VS 2010 team couldn’t provide DEV’s this feature… - Okay lets see what VS 2010 provides us when I select Calendar List and Events asItemAdded, ItemUpdated and ItemUpdating. VS 2010 created a .cs file and an Elements.xml file. Lets look at the .xml file created
<?xml version="1.0" encoding="utf-8"?> <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <Receivers ListTemplateId="106"> <Receiver> <Name>MyCustomEventReceiverItemUpdating</Name> <Type>ItemUpdating</Type> <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly> <Class>MyCustomEventReceiver.MyCustomEventReceiver.MyCustomEventReceiver</Class> <SequenceNumber>10000</SequenceNumber> </Receiver> <Receiver> <Name>MyCustomEventReceiverItemAdded</Name> <Type>ItemAdded</Type> <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly> <Class>MyCustomEventReceiver.MyCustomEventReceiver.MyCustomEventReceiver</Class> <SequenceNumber>10000</SequenceNumber> </Receiver> <Receiver> <Name>MyCustomEventReceiverItemUpdated</Name> <Type>ItemUpdated</Type> <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly> <Class>MyCustomEventReceiver.MyCustomEventReceiver.MyCustomEventReceiver</Class> <SequenceNumber>10000</SequenceNumber> </Receiver> </Receivers> </Elements>
As you would see the EventReceiver created is against ListTemplateId = 106 since I selected Calendar List. Next we will see what we need to do to register against a content type - Look at the code below which is modified to add a GUID on top of the class name. You can create a GUID using External Tools—>Create GUID from VS IDE
Note: The namespace System.Runtime.InteropServices; has been added. In the example below I am changing the tile to be automated based on the Title and current month and year.
using System; using System.Security.Permissions; using System.Runtime.InteropServices;–>NAMESPACE using Microsoft.SharePoint; using Microsoft.SharePoint.Security; using Microsoft.SharePoint.Utilities; using Microsoft.SharePoint.Administration; using System.Data; namespace MyCustomEventReceiver.MyCustomEventReceiver { /// <summary> /// List Item Events /// </summary> [Guid("db9b8706-8d95-40ff-9e93-1a7335af7a3b")] –>GUID ADDED HERE public class MyCustomEventReceiver : SPItemEventReceiver { /// <summary> /// An item was added. /// </summary> public override void ItemAdded(SPItemEventProperties properties) { setPropertiesOnDocument(properties); } private void setPropertiesOnDocument(SPItemEventProperties properties) { SPWeb web = properties.Web; try { SPListItem item = properties.ListItem; web.AllowUnsafeUpdates = true;
item["Title"] = item["Title"] +
"_" + DateTime.Now.Month
+ "_" + DateTime.Now.Year;
web.AllowUnsafeUpdates = false; } catch (Exception ex) { SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("MyEventReceiver", TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, ex.Message, ex.StackTrace); } finally { this.EventFiringEnabled = true; web.AllowUnsafeUpdates = false; } } /// <summary> /// An item was updated. /// </summary> public override void ItemUpdated(SPItemEventProperties properties) { setPropertiesOnDocument(properties); } /// <summary> /// An item is being updated /// </summary> public override void ItemUpdating(SPItemEventProperties properties) { SPListItem item = properties.ListItem; if (item["Title"] != null ) properties.AfterProperties["Title"] = item["Title"]; } } }
The last step is for you to think why I added the GUID on top of the class name. Visual Studio 2010 has been using a lot of these generate AssemblyFullName and AssemblyClassName . Look into the elements.xml file which has $SharePoint.Project.AssemblyFullName$ for the AssemblyFullName. Also an excellent reference from MSDN on Visual Studio 2010 Replaceable Parameters
- When we had added the EventReceiver it created a feature to deploy“MyCustomEventReceiver”. See below and we would remove the “MyCustomEventReceiver”from the feature1
- Now instead we will use a feature receiver to deploy our custom event receiver.
- Before we write any code we would need to go Feature1.Template.xml and add the replaceable parameters, make sure the GUID is LOWER CASE and is from the class file of your custom event receiver.
<?xmlversion="1.0" encoding="utf-8" ?>
<Featurexmlns="http://schemas.microsoft.com/sharepoint/">
<Properties>
<PropertyKey="GloballyAvailable" Value="true" />
<Property
Key="AssemblyQualifiedName"
Value=
"$SharePoint.Type.db9b8706-8d95-40ff-9e93-1a7335af7a3b.AssemblyQualifiedName$"/>
<Property
Key="AssemblyFullName"
Value="$SharePoint.Project.AssemblyFullName$"/>
</Properties>
</Feature>
<Featurexmlns="http://schemas.microsoft.com/sharepoint/">
<Properties>
<PropertyKey="GloballyAvailable" Value="true" />
<Property
Key="AssemblyQualifiedName"
Value=
"$SharePoint.Type.db9b8706-8d95-40ff-9e93-1a7335af7a3b.AssemblyQualifiedName$"/>
<Property
Key="AssemblyFullName"
Value="$SharePoint.Project.AssemblyFullName$"/>
</Properties>
</Feature>
Okay here is the code which would register your event handler to the content type on"FeatureActivated" and un-register on "FeatureDeactivating" .
using System; using System.Runtime.InteropServices; using System.Security.Permissions; using Microsoft.SharePoint; using Microsoft.SharePoint.Security; using System.Collections.Specialized; using Microsoft.SharePoint.Administration; using System.Collections; namespace MyCustomEventReceiver.Features.Feature1 { /// <summary> /// This class handles events raised during feature activation, deactivation, installation, uninstallation, and upgrade. /// </summary> /// <remarks> /// The GUID attached to this class may be used during packaging and should not be modified. /// </remarks> /// [Guid("f9df7585-b533-4706-a28e-5bcdb732c8f0")] public class Feature1EventReceiver : SPFeatureReceiver { // Uncomment the method below to handle the event raised after a feature has been activated. string asmblyFullNm = string.Empty; string clsNm = string.Empty; public override void FeatureActivated(SPFeatureReceiverProperties properties) { try { SPWeb web = properties.Feature.Parent as SPWeb; ReplaceParameters(properties.Feature.Properties); SPListCollection lstCollection = web.Lists; foreach (SPList lstToUpdate in lstCollection) { if (lstToUpdate.ContentTypes["MyCustomCalendarContentType"] != null) { SPEventReceiverDefinitionCollection defColl = lstToUpdate.EventReceivers; SPEventReceiverDefinition defToDelete = null; bool found = false; for (int k = 0; k < defColl.Count; ++k) { defToDelete = defColl[k]; if (defToDelete.Type == SPEventReceiverType.ItemAdded) { found = true; break; } } if (found) { defToDelete.Delete(); } defColl = lstToUpdate.EventReceivers; found = false; for (int k = 0; k < defColl.Count; ++k) { defToDelete = defColl[k]; if (defToDelete.Type == SPEventReceiverType.ItemUpdated) { found = true; break; } } if (found) { defToDelete.Delete(); } defColl = lstToUpdate.EventReceivers; found = false; for (int k = 0; k < defColl.Count; ++k) { defToDelete = defColl[k]; if (defToDelete.Type == SPEventReceiverType.ItemUpdating) { found = true; break; } } if (found) { defToDelete.Delete(); } defColl = lstToUpdate.EventReceivers; found = false; for (int k = 0; k < defColl.Count; ++k) { defToDelete = defColl[k]; if (defToDelete.Type == SPEventReceiverType.ItemDeleted) { found = true; break; } } if (found) { defToDelete.Delete(); } defColl = lstToUpdate.EventReceivers; found = false; for (int k = 0; k < defColl.Count; ++k) { defToDelete = defColl[k]; if (defToDelete.Type == SPEventReceiverType.ItemAdded) { found = true; break; } } if (found) { defToDelete.Delete(); } SPEventReceiverDefinition def = lstToUpdate.EventReceivers.Add(); string[] classNames = clsNm.Split(','); string className = classNames[0]; def.Assembly = asmblyFullNm; def.Class = className; def.Name = "ItemAddedMyCustomEventReceiver"; def.Type = SPEventReceiverType.ItemAdded; def.SequenceNumber = 1000; def.Synchronization = SPEventReceiverSynchronization.Asynchronous; def.Update(); def = lstToUpdate.EventReceivers.Add(); classNames = clsNm.Split(','); className = classNames[0]; def.Assembly = asmblyFullNm; def.Class = className; def.Name = "ItemUpdatedMyCustomEventReceiver"; def.Type = SPEventReceiverType.ItemUpdated; def.SequenceNumber = 1000; def.Synchronization = SPEventReceiverSynchronization.Asynchronous; def.Update(); def = lstToUpdate.EventReceivers.Add(); classNames = clsNm.Split(','); className = classNames[0]; def.Assembly = asmblyFullNm; def.Class = className; def.Name = "ItemUpdatingMyCustomEventReceiver"; def.Type = SPEventReceiverType.ItemUpdating; def.SequenceNumber = 1000; def.Synchronization = SPEventReceiverSynchronization.Synchronous; def.Update(); def = lstToUpdate.EventReceivers.Add(); classNames = clsNm.Split(','); className = classNames[0]; def.Assembly = asmblyFullNm; def.Class = className; def.Name = "ItemDeletedMyCustomEventReceiver"; def.Type = SPEventReceiverType.ItemDeleted; def.SequenceNumber = 1000; def.Synchronization = SPEventReceiverSynchronization.Asynchronous; def.Update(); } } } catch (Exception eEX) { SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("MyCustomFeatureReceiver", TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, eEX.Message, eEX.StackTrace); } } private void ReplaceParameters(SPFeaturePropertyCollection properties) { clsNm = properties["AssemblyQualifiedName"].Value; asmblyFullNm = properties["AssemblyFullName"].Value; } // Uncomment the method below to handle the event raised before a feature is deactivated. public override void FeatureDeactivating(SPFeatureReceiverProperties properties) { } } }
No comments:
Post a Comment