Azure Mobile Services – Paging with REST APIs

Mobile Services
I would like to complete the code I’ve provided to call the REST APIs for Windows Azure Mobile Services in my two previous posts, Introduction to Windows Azure Mobile Services and Windows Azure Mobile Services – Update with REST APIs. Today, I’ve been facing a basic mistake I made for my application Earthquakes. You are more and more everyday to use this application, and I thank you for that :). Each time a new user start the application, the app will register on Azure Mobile Services in order to update the Live Tile on the Phone (see the picture below). It means I store a list of URLs on Mobile Services, and I’ll contact these URLs to update the Live Tile on your phone.

Earthquakes Live Tiles
If you’ve read and use the source code I’ve provided you’ve probably noticed an issue. How do you retrieve a list of more than 50 entries in Mobile Services? You have two possibilities:

  • The first idea would be to increase the number of items you want to retrieve when you call the REST API. In order to do that you have to specify the parameter $top of the REST API. You can ask up to 1000 items in one call. But what’s going on if you have more than a thousand items in your base? You’ll simply never get them and it’s what happened to me. I was stuck with the 50 firsts items…
    URL format: https://<ServiceName>.azure-mobile.net/tables/<TableName>?$top=<Limit>
  • The other idea and probably the better in most of the cases, is to use paging. The paging capability allows you to retrieve your elements by lot, 50 at a time for example, until you have all of them. To do so, we will combine the attributes $top and $skip. Also, by using the attribute $inlinecount with the value allpages we will get the number of elements in the table at each call. It will help us to track if we need to perform more call to get more elements.
    URL format: https://<ServiceName>.azure-mobile.net/tables/<TableName>?$top=<Limit>&$skip<Skip>&$inlinecount=allpages

Let’s start coding with a class named RestResult that we will use to deserialize the elements including the number of elements in the table.

[DataContract]
public sealed class RestResult<T>
    where T : class
{
    [DataMember(Name = "results")]
    public T[] Results { get; set; }

    [DataMember(Name = "count")]
    public int Count { get; set; }
}

Now, we can update the function Get to retrieve an object RestResult<T> that will contain the list of elements we asked and the number of elements in the table.

public RestResult<T> Get<T>(string tableName, string filter = "", int skip = 0, int top = 50)
    where T : class
{
    if (!string.IsNullOrWhiteSpace(filter))
        filter = string.Concat("&$filter=", filter);

    Uri address = new Uri(string.Format("https://{0}.azure-mobile.net/tables/{1}?$inlinecount=allpages&$skip={2}&$top={3}{4}",
                                        ServiceName, tableName, skip, top, filter));

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(address);

    request.Method = "GET";
    request.Headers = new WebHeaderCollection
                            {
                                {"X-ZUMO-APPLICATION", ApplicationId},
                                {"X-ZUMO-MASTER", MasterKey},
                            };

    RestResult<T> result;

    using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
    {
        Stream stream = response.GetResponseStream();

        result = stream.Deserialize<RestResult<T>>();
    }

    return result;
}

And to finish, here is the code that will retrieve all the elements of a table.

public IEnumerable<T> GetAll<T>(string tableName, string filter = "")
    where T : class
{
    List<T> result = new List<T>();
    bool needMore;

    do
    {
        var get = Get<T>(tableName, filter, result.Count);
        result.AddRange(get.Results);

        needMore = get.Count > result.Count;
    } while (needMore);

    return result;
}