none
How to detect and resolved conflict at runtime in File Sync Framework? RRS feed

  • Question

  • Hi,

    My requirement.

    During bidirectional Synchronization if there in any type of conflict in any number of files, I need to show those files to user, and ask for ConflictResolutionAction that he want for particular file and need to implement that Action to file.

    So,

    1.) How to detect the list of conflict files and type of conflict at runtime.

    2.) And apply the ConflictResolutionAction at runntime.

    Thanks in advance

    Munish Bhargav 

     


    Saturday, November 19, 2011 7:42 AM

Answers

  • quick sample for you:

    class Program
        {
            private static Dictionary<string, string> filesInConflict = new Dictionary<string, string>();
            private static bool inPreviewMode = false;
    
            static void Main()
            {
                var sourceDir = new FileSyncProvider(@"c:\labs\source", null, FileSyncOptions.None);
                var destinationDir = new FileSyncProvider(@"c:\labs\dest", null, FileSyncOptions.None);
    
                //specify handler for conflicts
                var destinationCallbacks = destinationDir.DestinationCallbacks;
                destinationCallbacks.ItemConflicting += OnItemConflicting;
    
                // set first pass in preview mode to grab conflicting files
                inPreviewMode = true;
                sourceDir.PreviewMode = true;
                destinationDir.PreviewMode = true;
    
                var agent = new SyncOrchestrator
                                {
                                    LocalProvider = sourceDir,
                                    RemoteProvider = destinationDir,
                                    Direction = SyncDirectionOrder.Upload
                                };
    
                agent.Synchronize();
    
                // this is where you show the user the files in conflict and have them specify how to resolve them
                var keys = new List<string>(filesInConflict.Keys);
                foreach (var key in keys)
                {
                    filesInConflict[key] = "SourceWins"; //hardcoding for now, replace this with what user specifies
                }
    
                // do actual sync.
                sourceDir.PreviewMode = false;
                destinationDir.PreviewMode = false;
                inPreviewMode = false;
    
                agent.Synchronize();
            }
    
            public static void OnItemConflicting(object sender, ItemConflictingEventArgs args)
            {
                if (inPreviewMode) //if in Preview mode, add the file in the list
                {
                    filesInConflict.Add(((IFileDataRetriever)args.SourceChangeData).AbsoluteSourceFilePath, "");
                }
                else //apply resolution as specified by user
                {
                    var fileInConflict = ((IFileDataRetriever)args.SourceChangeData).AbsoluteSourceFilePath;
                    var resolution = filesInConflict.FirstOrDefault(f => f.Key == fileInConflict).Value;
    
                    if (!String.IsNullOrEmpty(resolution))
                    {
                        switch (resolution)
                        {
                            case "SourceWins":
                                args.SetResolutionAction(ConflictResolutionAction.SourceWins);
                                break;
    
                            case "DestinationWins":
                                args.SetResolutionAction(ConflictResolutionAction.DestinationWins);
                                break;
                            case "SkipChange":
                                args.SetResolutionAction(ConflictResolutionAction.SkipChange);
                                break;
                        }
                    }
                }
            }
    
        }
    

     

    • Marked as answer by Munish Bhargav Tuesday, December 6, 2011 7:36 AM
    Thursday, November 24, 2011 12:21 PM
    Moderator
  • you should register event handlers for ItemConflicting and ItemConstraint.

    see the section Handling Conflicts in the docs: http://msdn.microsoft.com/en-us/library/ee617386(v=sql.110).aspx

     

    • Marked as answer by Munish Bhargav Tuesday, December 6, 2011 7:36 AM
    Monday, November 21, 2011 1:16 AM
    Moderator
  • try setting the PreviewMode on the FileSyncProvider. this will simulate a sync without actually writing the files.
    • Marked as answer by Munish Bhargav Tuesday, December 6, 2011 7:36 AM
    Monday, November 21, 2011 10:32 AM
    Moderator
  •  if both files has been deleted on both sides, what do you need to present to the user to resolve that conflict?

    the FileData class has Creation, LastAccess and LastWrite times.

    i dont think the FileSyncProvider uses the merge option

    • Marked as answer by Munish Bhargav Tuesday, December 6, 2011 7:36 AM
    Friday, November 25, 2011 5:30 PM
    Moderator

All replies

  • you should register event handlers for ItemConflicting and ItemConstraint.

    see the section Handling Conflicts in the docs: http://msdn.microsoft.com/en-us/library/ee617386(v=sql.110).aspx

     

    • Marked as answer by Munish Bhargav Tuesday, December 6, 2011 7:36 AM
    Monday, November 21, 2011 1:16 AM
    Moderator
  • Thanks June for reply,

    Yes i catch the all conflicts at ItemConflicting Event handler when syncOrchestrator.Synchronize(); was called. but I need to present all the conflicts to users at once so that he take the decision on each file in conflict and on submit  apply Action on them once. 

    Is it possible If yes please let me know..

     

    Let me explian.

    Suppose during Sync there are n conflicts.

    When syncOrchestrator.Synchronize(); was called it called OnItemConflicting changes n times and after n calls it sync according to Action we specify. So what i did i collect all the args in OnItemConflicting handler so that i can present all the conflicts to user after n iteration. But i am not able to get the last count of n after which i need to present conflicts to user. 

    Or If you have other way to solve it then please let me know.

    Thanks in advance.

    Munish Bhargav

    Monday, November 21, 2011 5:42 AM
  • try setting the PreviewMode on the FileSyncProvider. this will simulate a sync without actually writing the files.
    • Marked as answer by Munish Bhargav Tuesday, December 6, 2011 7:36 AM
    Monday, November 21, 2011 10:32 AM
    Moderator
  • I want to set the PreviewMode to true only when the conflict arise. What is the best place to do that and where (means which event handler) to resolve that. Please suggest something.

    Thanks 

    Munish Bhargav

    Wednesday, November 23, 2011 5:29 AM
  • you cant toggle the sync from an actual sync to a preview mode only when you have called synchronize already. a conflict is fired when a sync session is already in progress.
    Wednesday, November 23, 2011 5:35 AM
    Moderator
  • So what will be the best way to present the conflict to user and resolve them according to action they take??
    Wednesday, November 23, 2011 5:50 AM
  • individually as the conflict occurs or do  a preview sync to get all potential conflicts
    Wednesday, November 23, 2011 6:01 AM
    Moderator
  • Could you please elaborate your views.

    If you provide some sample for the same then i shall be very thankful to you..


    Wednesday, November 23, 2011 6:18 AM
  • individually - you would register for the ItemConflicting and ItemConstraint events. as each conflict occurs, you tell the user and you set the conflict resolution accordingly.

    preview - run the sync in preview mode and registering for the same events as above and as each conflict occurs, you add them to a list. you then present to the user the list of conflicst and they chose how to resolve it. you then run a regular sync and as each conflict arises, you would set the resolution based on what the user previously specified when you presented the list of conflicts.


    Wednesday, November 23, 2011 6:25 AM
    Moderator
  • Thanks June for your help.

    I am able to Set the preview mode  when and where required and even able to retrieve the conflicted files in ApplyingChange handler with your helpful suggestions.

    Now i just need to compare the files in the list and during its relative OnItemConflicting Handlers and apply the corresponding changes. The issue i am facing that the "SourceChangeData" property of "ItemConflictingEventArgs" in OnItemConflicting throwing "Out of range exception is called more then once.

    Explanation:

    # Suppose i have more the one Conflict in my source folder.

    # Initially I setup the Preview mode to true and add all the conflict data in an list in "ApplyingChange" handler and present to user to take decision .

    # then set the preview mode to false

    # again compare the conflicted files with files in list to apply the relative action.

    But When OnItemConflicting handler called for then once its SourceChangeData property which caontain all the metadata for the file in conflict shows the out of range exception.

    Actual error is:

    Specified argument was out of the range of valid values Parameter name: unmanagedData.

    Please suggest something why its happening and what the solution of this. 

    Wednesday, November 23, 2011 10:28 AM
  • you might want to post some code snippets... i cant picture how you actually implemented the 2nd sync

    Wednesday, November 23, 2011 11:14 AM
    Moderator
  • I just setting some flags in DetectChanging and ItemConflicting methods to get it done. Here is code in ItemConflicting handler

            public static void OnItemConflicting(object sender, ItemConflictingEventArgs args)
            {
                if (mFileData.Count != 0)
                {
                    getConflict = (from fileData in mFileData
                                   where fileData.CurrentFileName == (args.SourceChangeData as Microsoft.Synchronization.Files.IFileDataRetriever).FileData.Name
                                   select fileData).First();
                    args.SetResolutionAction(getConflict.ResolutionAction);
                    mFileData.Remove(getConflict);
                    if (mFileData.Count == 0) mItemConflicted = false;
                }
                if (!mPreviewMode)
                {
                    args.SetResolutionAction(ConflictResolutionAction.SkipChange);
                    mPreviewMode = true;
                }
            }
    


    # Initially the mPreview Mode is set False. so syncing work awesome.

    #when conflict occurs it set the preview mode to true and ResolutionAction to Skipchanges. so during no change occurs

    #during next sync the conflicts are audit and saved in the List at Applying Changes handler. and present those conflict to users

    #Now when there are items in list set the preview mode to false and in Itemconflicting handler compare and set the resolution acc. but when there are more then one conflict the args does not present the proper args.

    Thursday, November 24, 2011 6:45 AM
  • quick sample for you:

    class Program
        {
            private static Dictionary<string, string> filesInConflict = new Dictionary<string, string>();
            private static bool inPreviewMode = false;
    
            static void Main()
            {
                var sourceDir = new FileSyncProvider(@"c:\labs\source", null, FileSyncOptions.None);
                var destinationDir = new FileSyncProvider(@"c:\labs\dest", null, FileSyncOptions.None);
    
                //specify handler for conflicts
                var destinationCallbacks = destinationDir.DestinationCallbacks;
                destinationCallbacks.ItemConflicting += OnItemConflicting;
    
                // set first pass in preview mode to grab conflicting files
                inPreviewMode = true;
                sourceDir.PreviewMode = true;
                destinationDir.PreviewMode = true;
    
                var agent = new SyncOrchestrator
                                {
                                    LocalProvider = sourceDir,
                                    RemoteProvider = destinationDir,
                                    Direction = SyncDirectionOrder.Upload
                                };
    
                agent.Synchronize();
    
                // this is where you show the user the files in conflict and have them specify how to resolve them
                var keys = new List<string>(filesInConflict.Keys);
                foreach (var key in keys)
                {
                    filesInConflict[key] = "SourceWins"; //hardcoding for now, replace this with what user specifies
                }
    
                // do actual sync.
                sourceDir.PreviewMode = false;
                destinationDir.PreviewMode = false;
                inPreviewMode = false;
    
                agent.Synchronize();
            }
    
            public static void OnItemConflicting(object sender, ItemConflictingEventArgs args)
            {
                if (inPreviewMode) //if in Preview mode, add the file in the list
                {
                    filesInConflict.Add(((IFileDataRetriever)args.SourceChangeData).AbsoluteSourceFilePath, "");
                }
                else //apply resolution as specified by user
                {
                    var fileInConflict = ((IFileDataRetriever)args.SourceChangeData).AbsoluteSourceFilePath;
                    var resolution = filesInConflict.FirstOrDefault(f => f.Key == fileInConflict).Value;
    
                    if (!String.IsNullOrEmpty(resolution))
                    {
                        switch (resolution)
                        {
                            case "SourceWins":
                                args.SetResolutionAction(ConflictResolutionAction.SourceWins);
                                break;
    
                            case "DestinationWins":
                                args.SetResolutionAction(ConflictResolutionAction.DestinationWins);
                                break;
                            case "SkipChange":
                                args.SetResolutionAction(ConflictResolutionAction.SkipChange);
                                break;
                        }
                    }
                }
            }
    
        }
    

     

    • Marked as answer by Munish Bhargav Tuesday, December 6, 2011 7:36 AM
    Thursday, November 24, 2011 12:21 PM
    Moderator
  • Thanks JuneT for your reply,

    Your sample works really great.. But i have few issue during sync as

    1.) Whenever I delete the same file from source as well as destination, so during sync conflict do arises not not able to log it as because args.SourceChangeData has out of bound exception so how to resolve that ???

     

    2.) Whenever We added a file having same name both in source as well as destination, it is't shows as conflict and overwrite the file with last change win policy i think?? How did you tackle with this?? 

    3.)  Also suppose there is Rename conflict But in ItemConflicting Handler the Conflict kind returns the update value. Try below line during Rename conflict.

    ConflictKind = ((ItemChange)args.DestinationChange).ChangeKind;
    

    4.) What is Merge Action and what is the best place to apply it? What is its effect if i apply it during Delete, Update and Rename??

     

     

    Friday, November 25, 2011 10:28 AM
  •  if both files has been deleted on both sides, what do you need to present to the user to resolve that conflict?

    the FileData class has Creation, LastAccess and LastWrite times.

    i dont think the FileSyncProvider uses the merge option

    • Marked as answer by Munish Bhargav Tuesday, December 6, 2011 7:36 AM
    Friday, November 25, 2011 5:30 PM
    Moderator