10

If someone ever had a similar experience, i'm trying to update word document in the document library and the problem is that my ItemUpdated is triggered multiple times. I think that last clientContext.ExecuteQuery() triggers the ItemUpdated again.?

My question is how to use this.EventFiringEnabled = false; in SharePoint 2013.

Here is the sample of my code:

public void ProcessOneWayEvent(SPRemoteEventProperties properties)
        {           
            using (ClientContext clientContext = TokenHelper.CreateRemoteEventReceiverClientContext(properties))
            {
                try
                {
                    List docLib = clientContext.Web.Lists.GetById(properties.ItemEventProperties.ListId);
                    ListItem item = docLib.GetItemById(properties.ItemEventProperties.ListItemId);
                    clientContext.Load(item);

                    clientContext.ExecuteQuery();

                    //This is just for testing i update word document here
                    item["Title"] = "NEW Title " + System.DateTime.Now.ToLongTimeString();
                    ////////////////////////////////////////////////
                    item.Update();

                    clientContext.ExecuteQuery();
                }
                catch (Exception oops)
                {
                    System.Diagnostics.Trace.WriteLine(oops.Message);
                }
            }
        }
    }

10 Answers 10

13
+125

I hade the exact same problem last week and found no built in way of solving it. What I ended up doing was checking the value of beforeProperties and afterProperties of what I wanted to update, and if there was no difference, then I broke out of the method. I actually wrote a blog post about it.

This is an annoying problem that I hope Microsoft improves in the future.

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);
                    }
                }
            }
        }
    }

And here's what checks for differences

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();
    }
  • Sounds like a fair solution. I was thinking about this too to nail the changes down. Will take a look at it and let you know. – Stefan Bauer Apr 8 '14 at 7:51
  • Expanded my answer with the method that checks for differences as well – stinaq Apr 8 '14 at 11:29
  • Unfortunately this doesn't work with a list since the before properties are null :( See below for a solution that may be a bit more Robust and simple. – TigerBear Dec 16 '16 at 11:32
2

this.EventFiringEnabled = false; is used in Server object model. However, there doesn't seem to be its equivalent in Client object model. So the alternative is to check the field value first before making any changes to avoid the update operation recurrence. See similar question here: http://social.technet.microsoft.com/Forums/exchange/en-US/7f21121c-6bef-4a2f-8ab9-58fc62768917/disable-item-updated-event-firing-during-item-updated-in-remote-event-receivers-in-sharepoint-2013?forum=sharepointdevelopment

Moreover, a better programming practice is to check the type of event first:

if (properties.EventType == SPRemoteEventType.ItemUpdated)

Otherwise your code will run for all "ed" events.

  • Thank you for your answer Nadeem. I use itemUpdated event to write some stuff to a word document in the document library list, in my sample code i have updated item "Title" just for testing purposes i have updated my question accordingly. And about your better programming practice comment... my Remote Event Receiver is registered on the list in App Installed event with EventReceiverDefinitionCreationInformation EventType set to ItemUpdated so it fires only when item is updated so i don't think that better programming practice is to check something that is always true – CalESharE Mar 28 '14 at 8:20
  • Checking the field value before making update will work only if the field you are updating is some flag or status kind of field. But for other fields will it work? – Unnie Mar 28 '14 at 8:46
  • ProcessOneWayEvent is called for all "ed" events. In general, if you have several events like added, deleted, then you will have to make a check for the type of event in order to execute relevant code. – Nadeem Yousuf Mar 28 '14 at 12:00
  • Yes but as i wrote earlier i added my Event Receiver in App Installed event with EventReceiverDefinitionCreationInformation (link) – CalESharE Mar 28 '14 at 12:52
  • Ok, I wasn't aware that you have only one event attached. I will still persist that making a check is better but of course when you have more than one type of event attached. – Nadeem Yousuf Mar 28 '14 at 13:00
2

Just an alternate workaround if nothing else works.Since there is no built in method which mimics this.EventFiringEnabled the only way is to set a flag outside this item which will enable us to know whether the current update event is called by a genuine update through browser or external code or from an update called from an update event.

  • Create another dummy list, with dummy 1 column "UpdatingID", which will store the ID of the document library item which is getting updated inside the ItemUpdated event reciever.
    • In the updated event receiver before you update the field of the current item, create a item in the Dummy list, with
      UpdatingID=current item id.
    • At the top of your ItemUpdated event reciever for document library, add a check whether any item exists in Dummy List with
      UpdatingID=Current ItemId , if No , run your logic for itemupdated,if YES delete that item(Since item will exist in dummy list event only if triggered by the update inside updated event receiver).
  • I found this article on MSDN, it is similar solution as Unnie suggested. Here is a link with sample code link – CalESharE Apr 15 '14 at 11:50
  • This solution really saved me !!! Tired of looking at limitations from Microsoft on so many utilities. – Bhaskar Dhone Jul 10 '16 at 5:45
0

Why don't you check item last updated date, if it is within last 1,2,3 minutes then skip updating the item second time ?

DateTime lastModifiedTime = Convert.ToDateTime(properties.ListItem["Modified"].ToString());

If(lastModifiedTime < DateTime.Now.AddMinutes(-2))
{
  // update the item
}
  • 1
    Good point but they fire right after each other. So this won't help much then. ;) You need to do the check based on milliseconds and cannot be sure if it is the first or one an additional call. So no solution that works. – Stefan Bauer Apr 8 '14 at 7:32
  • @StefanBauer off course you can use miliseconds in above example too.. DateTime.Now.AddMilliSeconds(-2) ;) – Muhammad Raja Apr 8 '14 at 8:10
  • 3
    Yeah I know but this will always be a wild guess instead of nail the calls down. ;) – Stefan Bauer Apr 8 '14 at 8:13
0

you can try something like this before your event receiver code

if (properties.AfterProperties["vti_sourcecontrolcheckedoutby"] == null 
&& properties.BeforeProperties["vti_sourcecontrolcheckedoutby"] != null) 
{ 
    //This is when the update event is triggered by check-in. 
} 
else 
{ 
    //This is triggered by events other than check-in action. 
}

sourceClick Here

0

I would use the adding or updating events. And then update the title within the "ProcessEvent":

public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties)
    {
        SPRemoteEventResult result = new SPRemoteEventResult();

            result.ChangedItemProperties.Add("Title", "NEW Title");
            result.Status = SPRemoteEventServiceStatus.Continue;
        return result;
    }

Read more here:

http://code.msdn.microsoft.com/office/SharePoint-2013-Add-list-2c6e71e0

0

You can use SPRemoteEventProperties.CorrelationId property

https://msdn.microsoft.com/en-us/library/office/microsoft.sharepoint.client.eventreceivers.spremoteeventproperties.correlationid.aspx

  • 1
    Link only answers are not very useful. Can you please include some description from the link. – Asad Refai Oct 13 '15 at 12:04
0

A workaround is here.

Add new column to the list LIST1 to which event triggers, say STATUS. On event triggering condition set its value as "Requested".

Now check STATUS field value in the event receiver. If its "Requested" then execute your code. then update STATUS field value to "Completed".

find the code below,

public void ProcessOneWayEvent(SPRemoteEventProperties properties)
{
    using (ClientContext clientContext = TokenHelper.CreateRemoteEventReceiverClientContext(properties))
    {
        if (clientContext != null)
        {
            clientContext.Load(clientContext.Web);
            clientContext.ExecuteQuery();

            if (properties.EventType == SPRemoteEventType.ItemUpdated) /* Process Item Update Event */
            {

                if (properties.ItemEventProperties.ListTitle == "LIST1") /* Checking for specific List Name */
                {
                    List reqList = clientContext.Web.Lists.GetById(properties.ItemEventProperties.ListId);
                    Microsoft.SharePoint.Client.ListItem item = reqList.GetItemById(properties.ItemEventProperties.ListItemId);
                    clientContext.Load(item);
                    clientContext.ExecuteQuery();

                    var eventStatus = item["STATUS"].ToString(); /* STATUS  */
                    if (eventStatus == "Requested")
                    {
                        //Your code to be executed.

                        //Update STATUS field value.
                        clientContext.Load(item);
                        clientContext.ExecuteQuery();
                        item["STATUS"] = "Completed";
                        item.Update();
                        clientContext.ExecuteQuery();
                    }

                }
            }
        }
    }
}
0

Unfortunately there aren't any beforeproperties for list events, so some of the solutions might not work.

A good solution is to make a hidden "EventReciever" property that doesn't display in any forms. Then edit this property within the Event Reciever. Now you just need to check the afterproperties and see if it contains your "EventReciever" property, since this property will now longer be included with any edits done by the GUI.

If you have other ways of editing this property, like through CSOM, then you can have your other code set this to false and your event reciever set this to true. Then you can check if it exists, and if so, is it set to true.

0

Why not check on userLoginName

if (!properties.ItemEventProperties.UserLoginName.Contains("app@sharepoint"))
{
    user did fire listitem update
}
else
{
    app fired the listitem update
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.