Windows Azure Mobile Services Offline Sync (Alpha)

In the recent build event, Microsoft announced a bunch of updates to its Azure stack. Today, I will focus on one of the most exciting features – Offline Sync on Mobile Services

As the name implies, it is an effort in the direction of providing out of the box offline sync capabilities for mobile applications which connect to Azure mobile services. Before this feature, one had to manually write all the plumbing code required to provide the seamless offline capabilities. Providing this out of the box feature will drastically reduce the time to market for many of the applications.

Two major requirements:

1. Backend services need to be hosted on Windows Azure mobile services. While this whole mobile service section is quite new on the stack, very few might be utilizing this service. For the new entrants on Azure, this can be an added services layer sitting right beside the existing WebAPI or WCF services which cater to the REST based requests. In fact Azure mobile services are heavily influenced by the Web API/MVC controller pattern.

2. SQLite DB is required on the device and nuget packages are available to create/access data from within the application. One can use Xamarin studios to develop cross platform native apps to utilize this feature also. Nuget packages for iOS, Android and WP are available to create and access SQLite database on all these platforms. In fact, these offline sync feature can be used in any windows application provided the above criteria holds good.

Setup:

  1. Server side:
    As said earlier, this service layer requires Controllers to handle requests, but these controllers will be derived from

    Microsoft.WindowsAzure.Mobile.Service.TableController<TableType>

    where TableType is nothing but the entity/table that needs to be transferred back and forth between the device. The focus of this blog post shall be mainly on the offline sync capabilities, so let’s jump on to that.

  2. Client side:
    To utilize the offline capabilities, server component has to be deployed as Azure mobile service. Once that is done, to create an instance of the mobile service client on the device, one needs these two bits of information ready at hand:

    1. Application url – This is the url at which the mobile service is deployed in Azure typically this would be something like – https://myawesomemobileservice>.azure-mobile.net
    2. ApplicationKey – Open the azure management portal and visit the mobile service dashboard page. When clicked on ‘MANAGE KEYS’ as shown in Fig 1, a popup will appear with the details on application key to be used as shown in Fig 2

 

Client side Execution

  1. At the start-up of the app, a one-time initialization operation needs to be performed:
    1. Create an instance of the SQLite store by calling –
      var store = new MobileServiceSQLiteStore("store4.data");
    2. Define a (syncable) Table in the store with the type as
      store.DefineTable<TableType>();

      Here [TableType] is the table that has shall contain some data which the user is expected to work with offline and sync later on. One can decide to have multiple such tables, but the lesser the better to avoid sync conflicts (explained later on).

    3. Initialize the SyncContext as
      this.client.SyncContext.InitializeAsync(store, new SyncHandler(this.client));

      SyncContext is an implementation provided by the framework which monitors on the changes done during offline mode by the user. Hence, we need to initialize it specifying the store and a custom SyncHandler (explained later in the post).

  2. Once the initialization is done, below code shall be called to get an instance of a table expected to monitor the offline changes done.
    var syncTable = this.client.GetSyncTable<TableType>();
  3. Further in the scope of the application, whenever user updates data in this table, the code below will be used to update the data
    syncTable.Someproperty = "Changed Value";
    syncTable.UpdateAsync();

     

    Synchronize with Server:

There are multiple steps involved to sync with the server for any offline changes performed.

  1. client.SyncContext.PushAsync();
    This will update the backend database with all the updates made, if any.
  2. syncableTable.PurgeAsync();
    This method will permanently remove items from the local database, as required .
  3. syncableTable.PullAsync();
    This method requires a query of what data has to be synced back from the server onto the device.

Note: The key difference between all the method API’s explained above is Push changes is called on the SyncContext while purge and pull are on table basis. While it provides granular control over what operation to be performed, it would have been better if Microsoft would have provided an out of the box method of syncing data across.

Something on the lines of –

client.SyncContext.Synchronize();

Handling synchronization conflicts

Any synchronization comes with its own set of conflicts occurring while the sync process proceeds. There could be other clients connected to the server and updating related data in which case, when this user syncs data conflicts will occur. Remember we had provided a custom SyncHandler class while initializing the Sync Context.

This class has to implement IMobileServiceSyncHandler having two methods like:

        public async Task<JObject> ExecuteTableOperationAsync(IMobileServiceTableOperation operation)
        {
            MobileServicePreconditionFailedException ex = null;
            JObject result = null;

            do
            {
                ex = null;
                try
                {
                    result = await operation.ExecuteAsync();
                }
                catch (MobileServicePreconditionFailedException e)
                {
                    ex = e;
                }

                if (ex != null)
                {
                    // There was a conflict in the server

                    var serverItem = ex.Value;

                    // Update the version of the pending item so that it won't have another
                    // conflict when the operation is retried.
                    operation.Item[MobileServiceSystemColumns.Version] = serverItem[MobileServiceSystemColumns.Version];

                    // One shall decide on a default action to be done in a conflict scenario. Server values override or client values overrides
                    // The client can be shown with some sort of UI to let the end user decide on what has to be done with the conflicting record!
                    // Finally, one has to update the final value to be updated in the server and re-do the ExecuteAsync operation.
                    operation.Item["notes"] = MergeNotes(thisNotes, serverNotes);
                }
            } while (ex != null);

            return result;
        }

The above method shall be called for each and every row that the SyncContext identifies as a modified row. Potentially this method can be called concurrently for each row. Hence one should be careful in the logic of conflict resolution not to be dependent on associated rows.

        public Task OnPushCompleteAsync(MobileServicePushCompletionResult result)
        {
            return Task.FromResult(0);
        }

As the name  implies, this method shall be called once after the completion of pushing the data back on to the server. We can hook into this method to update the UI or anything similar if required.

So on the whole, this feature is quite exciting, enabling a lot of hard to implement scenarios right out of the box. There exists some room for improvements too, but given that this is still in alpha release, we can anticipate some more enhancements to this feature making it flawless in the future.

What do you think about this feature?

Is Microsoft going in the right direction?

Do share your comments

The following two tabs change content below.

Rajesh Guptha