Skip to content

05 How to manage conflicts

Sébastien Pertus edited this page May 28, 2014 · 1 revision

How to manage Conflicts

All the conflicts are handled by the server side. You will have to edit your sync service server Handler file.

You should have a DefaultScopeSyncService.svc handler and its code file DefaultScopeSyncService.svc.cs file.

We will add some code to the .svc.cs file

Interceptors

Conflicts resolutions are managed with interceptors. Interceptors are methods decorated with customs attributes

Here is the customs attributes you can use :

[SyncInterceptor("DefaultScope", SyncOperations.Upload)]
[SyncResponseInterceptor("DefaultScope", SyncOperations.Download)]
[SyncRequestInterceptor("DefaultScope", SyncOperations.Download)]
[SyncConflictInterceptor("DefaultScope")]

Each Interceptor method as its own signature.

Here is one interceptor sample:

This method is invoked on an upload request before applying changes to the store.

This can be used to perform validations on the incoming entities and reject certain entities or abort the request.

        [SyncRequestInterceptor("DefaultScope", SyncOperations.Upload)]
        public void Upload_Request(SyncOperationContext context)
        {
            // Add a dummy header to the response indicating that the interceptor method was invoked.
            // Note: type casting the context to SyncUploadResponseOperationContext gives you access to the incoming entities and 
            // also enables you to reject entities based on custom logic.
            ((SyncUploadRequestOperationContext)context).ResponseHeaders.Add("UploadRequestInterceptorFired", "true");
        }

To handle conflicts, the interceptor required is SyncConflictInterceptor :

The method used must containes two parameters : a SyncConflictContext object and an IOfflineEntity merge entity.

The SyncConflicContext will contains the server side Entity and the client side Entity :

            ServiceTickets ticketClient = context.ClientChange as ServiceTickets;
            ServiceTickets ticketServer = context.ServerChange as ServiceTickets;

the merge Entity will contains a new Entity merged from server side and client side (if you decide to)

In a nutshell, you have 3 solutions to resolve your conflicts :

  1. Decide that the server is the winner of the conflict
  2. Decide that the client is the winner of the conflict
  3. Decide that the server Entity and the client Entity should be merged

The mergedEntity is used as the winner of the conflict when this method returns SyncConflictResolution.Merge as the resolution.

For other resolutions such as SyncConflictResolution.ClientWins and SyncConflictResolution.ServerWins the mergedEntity should be set to null.

Here is a sample to resolve a conflict on a particular Entity (ServiceTicket for instance) :

        public SyncConflictResolution ConflictHandler(SyncConflictContext context, out IOfflineEntity mergedEntity)
        {
            ServiceTickets ticketClient = context.ClientChange as ServiceTickets;
            if (ticketClient != null)
            {
                ServiceTickets ticketServer = context.ServerChange as ServiceTickets;

                ServiceTickets mergedTicket = new ServiceTickets();
                mergedTicket.Closed = ticketClient.Closed;
                mergedTicket.CustomerID = ticketClient.CustomerID;
                mergedTicket.Description = ticketClient.Description;
                mergedTicket.EscalationLevel = ticketClient.EscalationLevel;
                mergedTicket.Opened = ticketClient.Opened;
                mergedTicket.ServiceMetadata = ticketServer.ServiceMetadata;
                mergedTicket.ServiceTicketID = ticketClient.ServiceTicketID;
                mergedTicket.StatusValue = ticketClient.StatusValue;
                mergedTicket.Title = "MERGING TO CHECK " + ticketClient.Title;

                mergedEntity = mergedTicket;

                return SyncConflictResolution.Merge;

            }

            mergedEntity = null;
            return SyncConflictResolution.ServerWins;
        }