1
votes

I'm using a Node.JS backend on Azure with Easy Tables. The table contains the required columns to support offline syncing. While testing the sync process I noticed that conflicts keep coming back even though I'm resolving them.

My test:

  • Pull table content from Azure to iOS and Android device
  • Change a record on iOS but don't sync back to Azure
  • Change the same record on Android and sync
  • Now sync iOS

As expected, the conflict is detected correctly and I catch a MobileServicePushFailedException. I am then resolving the error by replacing the local item with the server item:

localItem.AzureVersion = serverItem.AzureVersion;
await result.UpdateOperationAsync(JObject.FromObject (localItem));

However, the next time I sync, the same item fails again with the same error.

The AzureVersion property is declared like this:

[Version]
public string AzureVersion { get; set; }

What exactly is result.UpdateOperationAsync() doing? Does it update my local database? Do I have to do it manually? And also: am I supposed to trigger an explicit PushAsync() afterwards?

EDIT: I changed the property from AzureVersion to Version and it works. I noticed that the serverItem's AzureVersion property was NULL even though the JSON contained it. Bug in Json.Net or in the Azure Mobile Client?

1

1 Answers

2
votes

You should be using something like the following:

public async Task SyncAsync()
{
    ReadOnlyCollection<MobileServiceTableOperationError> syncErrors = null;

    try
    {
        await this.client.SyncContext.PushAsync();

        await this.todoTable.PullAsync(
            //The first parameter is a query name that is used internally by the client SDK to implement incremental sync.
            //Use a different query name for each unique query in your program
            "allTodoItems",
            this.todoTable.CreateQuery());
    }
    catch (MobileServicePushFailedException exc)
    {
        if (exc.PushResult != null)
        {
            syncErrors = exc.PushResult.Errors;
        }
    }

    // Simple error/conflict handling. A real application would handle the various errors like network conditions,
    // server conflicts and others via the IMobileServiceSyncHandler.
    if (syncErrors != null)
    {
        foreach (var error in syncErrors)
        {
            if (error.OperationKind == MobileServiceTableOperationKind.Update && error.Result != null)
            {
                //Update failed, reverting to server's copy.
                await error.CancelAndUpdateItemAsync(error.Result);
            }
            else
            {
                // Discard local change.
                await error.CancelAndDiscardItemAsync();
            }

            Debug.WriteLine(@"Error executing sync operation. Item: {0} ({1}). Operation discarded.", error.TableName, error.Item["id"]);
        }
    }
}

Note the CancelAndUpdateItemAsync(), which updates the item to the server copy or CancelAndDiscardItemAsync(), which accepts the local item. These are the important things for you.

This code came from the official HOWTO docs here: https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-dotnet-how-to-use-client-library/##offlinesync