Detecting CopyMove in SharePoint Event Receivers

Top  Previous  Next

Custom event receivers or third-party event receivers in SharePoint lists will conflict with CopyMove if they make any updates in asynchronous events like ItemAdded and ItemUpdated before CopyMove is done with the item. This is especially true when copying or moving documents and items with more than one version. CopyMove does have some retry logic to recover from conflicts - but it does not cover all possible scenarios. To avoid conflicts, custom event receivers must implement CopyMove awareness to defer all work until CopyMove has imported the last document or item version.

The CopyMove awareness can be implemented by monitoring the value of the item property named SPPCopyMoveEvent that CopyMove injects into property bag of each list item version being imported. However, the property injection is not enabled by default. It must first be enabled with the following PowerShell command in a SharePoint Management Shell on the SharePoint server:

Set-CopyMoveSettings -InjectEventProperties

 

Once enabled, CopyMove will inject the property to all items being copied and moved. The property can assume the different values shown in the table below.

Value

Events

Description

0

ItemAdded

ItemCheckedIn

File was copied (last version will have this value)

1

ItemAdded

ItemCheckedIn

File was moved (last version will have this value)

2

ItemUpdated

Move in progress (more versions to be imported)

3

ItemUpdated

Copy in progress (more versions to be imported)

4

ItemUpdated

The very last event after a copy

5

ItemUpdated

The very last event after a move

Code wise, the SPPCopyMoveEvent property can be monitored as shown in the following C# code sample.

public class SampleEventReceiver : SPItemEventReceiver

{

    public override void ItemAdded(SPItemEventProperties properties)

    {

        HandleCopyMoveEvent(properties.AfterProperties);

    }

 

    public override void ItemUpdated(SPItemEventProperties properties)

    {

        HandleCopyMoveEvent(properties.AfterProperties);

    }

 

    private void HandleCopyMoveEvent(SPItemEventDataCollection properties)

    {

        object sppCopyMoveEventObj = properties["SPPCopyMoveEvent"];

        if (sppCopyMoveEventObj != null)

        {

            int copyMoveEventId;

            if (Int32.TryParse(sppCopyMoveEventObj.ToString(), out copyMoveEventId))

            {

                HandleCopyMoveEvent(copyMoveEventId);

            }

        }

    }

 

    private void HandleCopyMoveEvent(int copyMoveEventId)

    {

        switch (copyMoveEventId)

        {

            case 0:   // Copying last item version

                break;

 

            case 1:   // Moving last item version

                break;

 

            case 2:   // Move in progress - more versions to come.

                break;

 

            case 3:   // Copy in progress - more versions to come.

                break;

 

            case 4:   // Copy complete.

                break;

 

            case 5:   // Move complete.

                break;

 

        }

    }

}