Microsoft has finally unveiled and released the early bits of Microsoft Azure Mobile Services’ Offline Data Support in last week’s Build conference.
I have been lucky enough to see and provide feedback on the early bits for offline support when I was invited to the Azure Mobile Services Advisory Board last year courtesy of Nick Harris (@cloudnick) and Mohamed Ahmed (@MohamedFAhmed).
Since then, I’ve been itching to see what comes out in the public release and blog about it.
It’s good to finally see something from Microsoft on the synchronization front again. The last time there was some buzz from Microsoft on this front was when they started working with what was supposed to be Sync Framework v4 (eventually released as open-source Sync Framework Toolkit) and Azure SQL Data Sync (which is in Preview for several years already)
Please note that this is not a tutorial or a guide on how to get started, but rather a summary of my notes while reviewing the sync functionality.
So here you go, a quick look at Azure Mobile Services Offline Data Support.
First, what it is not:
- it’s not a full feature database synchronization/replication solution
- it’s not a stand-alone synchronization SDK, it’s part of Azure Mobile Services
- it’s not based on Sync Framework unlike Azure SQL Data Sync
- it’s not meant to replace and be feature equivalent to Sync Framework, Azure Data Sync or SQL Replication
- it’s not RTM yet
Which client SDK and data store does it support:
On the Client side, it’s SQLite and on .NET SDK clients for now, other clients to come next. The SDK has an interface for the client database support as well, so developers can presumably add other client database platforms.
Server side would include presumably any of the supported back-ends like SQL Database , MongoDB and Azure Table Storage (based on what’s supported in the .NET backend support and whatever developers can plug-in in the future)
The sync functionality is almost exclusively on the client SDK, so there’s really no backend-store specific in the synchronization implementation.
What sync operations are supported:
The SDK supports Push (Upload), Pull (Download) and Local Purge operations and sync has to be explicitly invoked.
- Explicit Invoke– Synchronization is not automatic or bound/triggered by network availability or some background tasks. A Synchronization has to be explicitly invoked to initiate the synchronization.
- Push (Upload) – push/upload is invoked for all local sync tables in sync context and you cannot selectively specify or restrict which local table or tables to upload
- Pull (Download)– this is invoked per table and you can specify a filter on what to pull/download. Note that a Pull will invoke a Push to upload local changes before initiating the pull/download operation
- Purge – this is not purely a synchronization action but can be used to clean up local data. You can specify a filter on what to purge and purge will invoke a Push as well to upload changes from local before doing the purge.
await localTable.PurgeAsync(localTable.Where(t => t.Complete));
How does it keep track of changes:
This is one of the best things I like as it’s a very lightweight and non-intrusive change tracking (by non-intrusive, i mean not having to change writing Create/Update/Delete code).
- Client Side
- Custom change tracking on SQLite
- 2 systemtablesare added ontheSQLite database
- “__operations” – serves as a queue to record insert/update/delete
- “__errors” – sync error recording
- Server Side
- Tracked using the same Version column/property introduced for Optimistic Concurrency (see: New tables in Azure Mobile Services: string id, system properties and optimistic concurrency)
- Row-level change tracking – note that the change tracking is done at the row level. So for an update operation, it only knows that a row was updated, not what/which columns were updated. Neither does the change tracking store copies of the row for every change (e.g., if you updated the row twice, it doesn’t store multiple versions of the row)
How do you prepare databases for synchronization:
- Client Side
- Include the Version column/property for every table to be synched
- Use SDK to create localSQLite database, specify tables to store locally and initialize sync context
var client = new MobileServiceClient(ApplicationUri, ApplicationKey)
var store = new MobileServiceSQLiteStore(localstorefilename)
- Server Side – nothing to do. As mentioned above, it uses the same Version column.
Do I need to change the way I code in Azure Mobile Services:
This is the best part of the SDK.
- No. not much really. You just have to change the way you instantiate the table objects: IMobileServiceTable<T>/GetTable<T> vs. IMobileServiceSyncTable<T>/GetSyncTable<T>. Apart from some overloads available on the online tables, the CRUD operations you do will almost be the same as if you were working with the online tables.
reference local vs remote table:
var localTable = client.GetSyncTable();
var remoteTable = client.GetTable();
- Plus, you always have the option of choosing to work with either the online or offline table, or even both.
How does it apply changes:
Changes go up and down in the same, existing REST-based mechanism that Azure Mobile Services has.
- the local changes are applied remotely in the same order the operations occurred in the client store (this is good specially for parent-child inserts as it makes sure that the parent that was inserted first is applied before the child)
- note that while there’s a local operations queue as mentioned above for tracking changes locally, the change application is not actually replaying the operations made to a row.e.g., if the local operations is an insert followed by an update, it will not apply or replay an insert and an update to the remote store, just a “merged” operation which is an insert on remote.if multiple updates are done locally before pushing the changes to the server, it will not replay X number of updates for the row and only the last update will get reflected.
Can it handle conflicts:
Yes, it does.
- Supports conflict detection and conflict resolution
- Local and remote copy of conflicting rows are available when a conflict is detected
- You can choose to retain local copy or apply remote copy
- Conflicts need to be resolved per row, there is no default or global conflict resolution policy
- see: Handle conflicts with offline data in Mobile Services
Can you batch changes:
- No OOTB batching support
- Syncs applied one row at a time, not as bulk operations
Is it extensible:
- the SDK has provisions for creating/supporting other client stores as well as sync handlers.
- Hats off to the Azure Mobile Services team for keeping thru to their goal of keeping it simple.
Where can i find more information:
- Blog: Deep dive on the offline support in the Azure Mobile Service managed client SDK
- Tutorial: Get started with offline data
- Tutorial: Handle conflicts with offline data in Mobile Services
- Video: Powerful Mobile Apps with Mobile Services and ASP.NET Web API
- Video: Building Cross-Platform Line of Business Apps with Mobile Services