30 Days of Zumo.v2 (Azure Mobile Apps): Day 25: The Push to Sync Pattern

In the last two articles, I’ve covered registering for push notifications and I’ve used the test send mechanism to send a push notification to the client. While useful for sending random marketing messages, you can also use push notifications to handle out of band sync notifications. Offline sync has the problem that you have to keep on polling for updates. What if, instead, you notified all your clients when something happened to a record and your client just polled when it received an update? This is the essence of the push to sync pattern. Once you have registration working, it’s remarkably easy to implement.

Step 1: Configure Push Registrations

I’ve already covered this piece. In my server, I’m going to override the push notification registration process so that a user tag is registered when my client registers. This will be used when I push. I’m not going to cover this here – I’ve already covered it in my last post.

Step 2: Push on Insert, Update or Delete

My first step in this process is to find the notification hub. I’m doing this in the table controller where I want the push operation. This could just as easily be a service registered for the purpose.

        private async Task PushToSync(string op, string id)
            var hub = Configuration.GetPushClient().HubClient;
            var emailAddr = await GetEmailAddress();
            var tag = $"_email_{emailAddr}";
            var installationId = Request.Headers.Where(p => p.Key.Equals("X-ZUMO-INSTALLATION-ID")).FirstOrDefault().Value.FirstOrDefault();

            // Construct a payload
            var payload = new PushToSyncPayload
                Message = "PUSH-TO-SYNC",
                Table = "todoitem",
                Operation = op,
                Id = id,
                Originator = installationId
            var jsonPayload = JsonConvert.SerializeObject(payload);

            // Push the request via the Notification Hub
            var outcome = await hub.SendGcmNativeNotificationAsync($"{{\"data\":{jsonPayload}}}", tag);

There is an additional class for this:

using Newtonsoft.Json;

namespace backend.dotnet.Controllers
    public class PushToSyncPayload
        [JsonProperty(PropertyName = "message")]
        public string Message { get; set; }
        [JsonProperty(PropertyName = "table")]
        public string Table { get; set; }
        [JsonProperty(PropertyName = "op")]
        public string Operation { get; set; }
        [JsonProperty(PropertyName = "id")]
        public string Id { get; set; }
        [JsonProperty(PropertyName = "orig")]
        public string Originator { get; set; }

Note that I am recording the Originator – this allows me to ensure the originator doesn’t do anything with the request. Now all I need to do is to call the PushToSync() method in my table controller. For example, here is my UPDATE operation:

        // PATCH tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959
        public async Task<TodoItem> PatchTodoItem(string id, Delta<TodoItem> patch)
            Debug.WriteLine($"PATCH tables/TodoItem/{id}");
            var item = Lookup(id).Queryable.FirstOrDefault<TodoItem>();
            if (item == null)
                throw new HttpResponseException(HttpStatusCode.NotFound);
            var emailAddr = await GetEmailAddress();
            if (item.UserId != emailAddr)
                throw new HttpResponseException(HttpStatusCode.Forbidden);
            var newItem = await UpdateAsync(id, patch);
            await PushToSync("PUT", id);
            return newItem;

If you run the code, then updating the record will generate a push that you can see on your client.

Step 3: Respond to the Push

Since the Apache Cordova code calls a routine when the push is received, all I need to do is add my handler to the code:

    function handlePushNotification(data) {
        if (data.message === 'PUSH-TO-SYNC') {

            var id = data.additionalData.id;
            var op = data.additionalData.op;
            var table = data.additionalData.table;
            var originator = data.additionalData.orig;
            if (originator !== client.getApplicationInstallationId()) {
                alert('OTHER:' + JSON.stringify(data));
            } else {
                alert('ME:' + JSON.stringify(data));
        } else {
            alert('PUSH NOTIFICATION\n' + data.message);

Now, I’m not doing anything with the information here. I could, for instance, call refreshDisplay() that just refreshes the data from the server. Since the Apache Cordova SDK does not have offline sync (yet), there is little point in doing anything more. However, in an offline sync version of the SDK, there is a little more you can do. For instance, instead of refreshing all the data from the server, you have enough information to pull a specific record. In the UWP version, this would be done with the following:

await syncTable.PullAsync(null, $"id={id}");

Id would be gathered from a JSON deserialization operation on the push result. The idea is to only pull (and update the offline sync cache) for the specific record that you want, avoiding the incremental sync and record push that would otherwise go along with the regular sync operation. This minimizes the number of network operations that are happening. This does not remove the need for regular sync operations (as the application may not be running at the time of the push). It reduces the amount of time between a database modification and the user noticing, plus it reduces the amount of network traffic caused by infrequent database updates (since you don’t need to poll as often to find out if there are any changes).

Next Steps

Next up on my list of things to do is to handle relationships in the ASP.NET application. There is a commonly requested pattern that is actually relatively difficult. I’ll go into the reasons it’s so hard and how to do it.

As always, my code is on my GitHub repository.

2 thoughts on “30 Days of Zumo.v2 (Azure Mobile Apps): Day 25: The Push to Sync Pattern

Comments are closed.