tl;dr: If you have trouble with stopping the updated-event from firing, compare what you want to change in the beforeProperties and afterProperties. If they are different, you should go ahead with your update, otherwise not.
This was my scenario: I had created a remote event receiver that was attached to a document library and was supposed to act whenever an item in the list was updated. The initialization of the event receiver looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 |
private static void AddEventReceiverDocLib(List documentLibrary) { var eventReceiverItemAdded = new EventReceiverDefinitionCreationInformation { EventType = EventReceiverType.ItemUpdated, ReceiverName = ReceiverNameItemAdded, ReceiverUrl = "someurl/Services/RemoteEventReceiverDocuments.svc", SequenceNumber = 1001, Synchronization = EventReceiverSynchronization.Asynchronous }; documentLibrary.EventReceivers.Add(eventReceiverItemAdded); } |
And all was fine in the world. The event receiver was nicely attached and got busy when I uploaded a document. But then it started acting out and making trouble. I was trying to change permissions on an item and this was the part of my code that was creating the problems:
1 2 |
item.BreakRoleInheritance(true, true); item.Update(); |
Inside my SPRemoteEventType.ItemUpdated I did an Update and making it trigger itself. Recursive SharePoint with no end in site.. If you’re dealing with a event receiver with access to server side code, this is not a problem.
1 |
this.EventFiringEnabled = false; |
Writing that makes your world pink and sparkly again. But this is the barren end empty world of the remote event receiver and no such this is available.
How I solved it
Googleing this helped me not one bit and my first solution was something I would like to hide at the bottom of some server (I don’t want to talk about it, let’s just say it had something to do with counting the seconds since the last update).
At your disposal on SPRemoteEventProperties you have afterProperties and beforeProperties, found by doing this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public void ProcessOneWayEvent(SPRemoteEventProperties properties) { using (ClientContext clientContext = TokenHelper.CreateRemoteEventReceiverClientContext(properties)) { if (clientContext != null) { if (properties.EventType.Equals(SPRemoteEventType.ItemUpdated)) { var afterProperties = properties.ItemEventProperties.AfterProperties; var beforeProperties = properties.ItemEventProperties.BeforeProperties; } } } } |
And those were the key to the problem: how to act on the firing only when the user changes something and not when it updates itself? By comparing the values in the beforeProperties with the afterProperties I could see if they contained a difference. If it doesn’t, the updating event should not happen again.
In my case I was changing the value of a custom property named CMIsSecret, so if that property was the same in beforeProperties as in afterProperties (the values before and after the save) I should go on with the update, otherwise not. This was the method I created:
1 2 3 4 5 6 7 8 9 10 11 12 |
private static bool ShouldSecretBeUpdated( IReadOnlyDictionary<string, object> beforeProperties, IReadOnlyDictionary<string, object> afterProperties) { // If the property doesn't exist, then the secret should be updated if (!beforeProperties.ContainsKey("CMIsSecret") || !afterProperties.ContainsKey("CMIsSecret")) { return true; } //// If the value of IsSecret differ, then secret should be updated return afterProperties["CMIsSecret"].ToString() != beforeProperties["CMIsSecret"].ToString(); } |
It checks if the property exists at all (it doesn’t if it is an ItemAdded-event and the property is custom made) and if it differs. It returns true if the property should be updated and the final usage looked like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public void ProcessOneWayEvent(SPRemoteEventProperties properties) { using (ClientContext clientContext = TokenHelper.CreateRemoteEventReceiverClientContext(properties)) { if (clientContext != null) { // When new case is added or updated, this is the method that gets triggered if (properties.EventType.Equals(SPRemoteEventType.ItemUpdated)) { var afterProperties = properties.ItemEventProperties.AfterProperties; var beforeProperties = properties.ItemEventProperties.BeforeProperties; if (ShouldSecretBeUpdated(beforeProperties, afterProperties)) { ChangePermissionSettings(properties, clientContext); } } } } } |
Where ”ChangePermissionSettings” changes and updates the item.
Hope it helps!