Thursday, March 4, 2010

Binding asynchronous event handlers as synchronous

In SharePoint, we know, there are two types of event receivers, asynchronous and synchronous, for example, the ItemUpdating and ItemUpdated. The ItemUpdating is synchronous while the ItemUpdated is asynchronous. The obvious difference is, the synchronous event is raised before committing the changes so that we have the opportunity to cancel whatever the the operation but not in the asynchronous event as that is raised after successfully committing the changes requested.

With that simple description I will dive direct to the specifics as there are plenty of information available about event handlers in SharePoint out there. From here on, I will make a safe assumption that you know about the event handler in SharePoint and also how to write simple event handler.

With that I will explain my finding on how to bind the asynchronous event handler as synchronous as this will help us in some scenarios.

By default, using the object model, we can register the event handlers by,

parentList.EventReceivers.Add(SPEventReceiverType.ItemAdded, Constants.AssemblyName.EventManagement, className);

parentList.Update()

This will bind the event handler to the list using the default binding depending on the type of the event, for example, if it is ItemAdding, binding is synchronous and ItemAdded the binding is asynchronous.

Another way of registering an event handler to a list is by creating an empty handler and setting the values separately,

//Create the event handler
itemAddedEventReceiver = parentList.EventReceivers.Add();

//Set the values for the item added event receiver
itemAddedEventReceiver.Name = NameOfItemAdded;

//Set the binding
itemAddedEventReceiver.Synchronization = SPEventReceiverSynchronization.Synchronous;

itemAddedEventReceiver.Type = SPEventReceiverType.ItemAdded;
itemAddedEventReceiver.Assembly = Constants.AssemblyName.EventManagement;
itemAddedEventReceiver.Class = className;
itemAddedEventReceiver.Update();

parentList.Update();

Main advantage of registering event handlers in the second way, is, probably obvious by now, we can change the binding, so we can register the asynchronous event handlers such as ItemAddeded with binding set to synchronous as below.

itemAddedEventReceiver.Synchronization = SPEventReceiverSynchronization.Synchronous;

This way it is guaranteed that both ItemAdding and ItemAdded are completed synchronously. The main advantage I found here is, consider the document library and if you need to perform an automatic operation whenever a new document is added, you can do that in the ItemAdded event handler and modify the the list item and save it with the modified data within ItemAdded event handler, this works well with the multiple document updated as the multiple document update raises only ItemAdding and ItemAdded, but in the case of single document upload, as a standard feature in document library, just after the document is uploaded, SharePoint opens the list item in property edit page to enter the new property values, now since we modify the list item in ItemAdded asynchronously, the version of the list item in the property edit page is not the one we saved in ItemAdded event handler as a result when we attempt to save the new properties, we will get the unfortunate save conflicts.

So this can be avoided by registering the ItemAdded event handler to work synchronously, then the property edit page will be opened with the updated list item and not the original one.

3 comments:

Anonymous said...

Just checking, what assembly did you have to include to use the Constants.AssemblyName.eventmangement? My two options are Microsoft.SharePoint.Help.Constants and Microsoft.SharePoint.BusinessData.MetadataModel.Constants neither of which have the AssemblyName in them...



Thanks!!

Wineya Wijesinghe said...

That is a local constant, you can use the fully qualified assembly name
eg EventManagement, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0000000000

EventManagement is the assembly name and replace the PublicKeyToken with the correct token.

George Begbie said...

While this seems like a great idea, I've discovered that it fails when using certain commands.

The SPFileCollection.Add() method often throws up strange Access Denied errors. The issue only occurs when I use normally asynchronous receivers in synchronous mode instead.