Writing...Data Services

Coding and writing about OData and now Windows Azure Mobile Services...

Mobile Services Custom Parameters in Windows Store apps

Mobile Services Custom Parameters in Windows Store apps

Rate This
  • Comments 1

Well, it’s now 2013, and I spent some time over the holidays messing around with using custom parameters in my mobile service…

Windows Azure Mobile Services makes it rather easy to both read data from and modify data in a mobile service by using HTTP requests to the CRUD operations: POST, GET, PATCH. and DELETE. GET requests use an OData-style query URI to select data, and POST is used to send a new JSON object to be inserted. Pretty simple stuff really, and the client libraries make it very easy to do in your apps.

Although it’s simple to get started, Mobile Services also provides a huge amount of flexibility to execute custom business logic in the backend that is triggered by these CRUD operations, by using server scripts. In particular, server scripts can inspect the incoming request and short-circuit, modify, or even cancel the requested operation. As Amit demonstrated previously in his post Custom Parameters in Azure Mobile Services, a request URI can include custom parameters that can be used by the client provide additional information to the mobile service to help it more correctly process the request.

The goal of this post is not to describe how custom parameters work (Amit has already done that) but to highlight the new client support in the Mobile Services SDK for Windows Store apps.

Handling custom parameters on the service-side

As I mentioned, Amit’s existing post already provides excellent information showing how to leverage custom parameters on the service-side, but just for the context of the examples in this post, here is the service script, registered to the insert function on the ubiquitous TodoItems table, that I am using to test:

function insert(item, user, request) {
  // Get the TodoItem table.
  var todoItemTable = tables.getTable('TodoItem');
  // Check the supplied custom parameter to see if
  // we should allow duplicate text items to be inserted. 
  if (request.parameters.duplicateText === 'false') {
      // Find all existing items with the same text
      // and that are not marked 'complete'. 
      todoItemTable.where({
          text: item.text,
          complete: false
      }).read({
          success: insertItemIfNotComplete
      });
  }
 
  function insertItemIfNotComplete(existingItems) {
      if (existingItems.length > 0) {
          // Because there is an existing item, which is not 
          // marked complete, block the insert and raise a 
          // 409 response to notify the client that 
          // the insert was not processed.
          request.respond(statusCodes.CONFLICT, 
          "Duplicate items are not allowed.");
      } else {
          // Insert the item as normal. 
          request.execute();
      }
  }
}

Notice that that for this insert request to the TodoItem table, we block duplicate inserts when a) this behavior is requested by the client by specifying the duplicateText=false parameter and b) the existing item is not yet marked as complete. Now, let’s see the goodness in the client. We also raise an error to notify the client that the insert essentially failed, which I’ll discuss more later on.

Adding custom parameters in a Windows Store app

Appending custom parameters to a request URI is a fairly trivial operation when you are composing your own URIs, but in Amit’s post (using filters and custom wrappers) you can see how difficult it used to be to include custom parameters in your requests. Mobile Services now makes it super-easy to attach custom parameters to your requests from a Windows Store app. Of course, the APIs look different depending on whether you are coding in C# or JavaScript….

Note: Since support for custom parameters in a Windows Store app is a fairly recent addition, you need to download the most recent version of the Mobile Services SDK. If you already have the SDK installed, it will simply overwrite the libraries.

Windows Store app in C#

The CUD operations methods now have a new overload that takes an IDictionary<string, string> that contains your custom parameters. The following example is based on the InsertTodoItem method from the Mobile Services quickstart, which has been updated to have the mobile service reject duplicate text values, when the item isn’t marked complete:

// Define a custom query parameter to prevent duplicate text.
Dictionary<string, string> myParam = new Dictionary<string, string>();
myParam.Add("duplicateText", "false");
 
// This code inserts a new TodoItem into the database. When the operation completes
// and Mobile Services has assigned an Id, the item is added to the CollectionView
await todoTable.InsertAsync(todoItem, myParam);
items.Add(todoItem);

This code also handles the MobileServiceInvalidOperationException that is returned when the item already exists. Note that support for parameters may not have yet made it into the WP8 client.

Windows Store app in JavaScript

In JavaScript, you also pass parameters into the CRUD methods, but as a JSON object, which is way easier than using a dictionary in .NET:

todoTable.insert(todoItem, { duplicateText: false }).done(function (item) {
    todoItems.push(item);
});

What about adding parameters to read (GET) requests?

I chose to focus on an insert (POST) operation rather than a read (GET) because (IMHO) the OData-based URI query syntax already gives you a great deal of flexibility in requesting data without having to resort to using custom parameters. Plus, Amit covered some existing read scenarios in his original post.

For queries, there is now a new WithParameters method on MobileServiceTableQuery<T> in the (C#) client, which lets you supply a dictionary of parameters to be added to the query request. This means that Amit’s original client query example now looks like this:

Dictionary<string, string> myParam = new Dictionary<string, string>();
myParam.Add("allUsers", "true");    
    
List<User> allUsers = await App.MobileService.GetTable<User>()
    .Skip(0).WithParameters(myParam).ToListAsync();

Note that in the C# client, we have to use a query method to get back a MobileServiceTableQuery<T> instance; I used Skip(0) in this workaround. Ideally, there would be a WithParameters() method on IMobileServiceTable<T> for cases where we wanted to execute a “default” table query with parameters.

For JavaScript clients, it’s as simple as passing the JSON parameters object to the read function:

todoTable.where({ complete: false })
    .read({ allUsers: true })
    .done(function (results) {
        todoItems = new WinJS.Binding.List(results);
        listItems.winControl.itemDataSource = todoItems.dataSource;
    });

And, yes, the MSDN docs have not yet caught up to the current version of the SDK…working in it.

Communicating a no-op to the client

The one design point in my insert script on the server that hung me up a little bit was deciding on what kind of response the insertItemIfNotComplete function should send when it prevented a duplicate insert. Because the client explicitly requested not to insert duplicates, I wanted to treat this as a “no-op” and return an HTTP 204 (NO_CONTENT). To me, this would indicate that an update was not made by the server and the client should not refresh its view (binding). However, the client treats any 200-level response as a success, and there is currently no way to inspect the result of an async CUD operation. Because of that, I went with returning an HTTP 409 (CONFLICT)—which seemed sort of to the point. That way, I could get hold of the response, make sure the error was really the expected 409, and then display a message box, as shown in the following code:

// Define a custom query parameter to prevent duplicate text.
Dictionary<string, string> myParam = new Dictionary<string, string>();
myParam.Add("duplicateText", "false");
 
try
{
    // This code inserts a new TodoItem into the database. When the operation completes
    // and Mobile Services has assigned an Id, the item is added to the CollectionView
    await todoTable.InsertAsync(todoItem, myParam);
    items.Add(todoItem);
}
catch (MobileServiceInvalidOperationException ex)
{
    if (ex.Response.StatusCode == 409)
    {
        var dialog = new MessageDialog(ex.Message);
        dialog.Commands.Add(new UICommand("OK"));
        dialog.ShowAsync();
    }
    else throw ex; 
}

I’m thinking of making a Mobile Services feature request to make the entire response accessible to the client from CUD operations. That way, I could inspect a success operation for specific success codes, like 204.

Take care,

Glenn Gailey
Leave a Comment
  • Please add 3 and 2 and type the answer here:
  • Post
  • When will WithParameters be added to the WP8 branch?

    thanks

Page 1 of 1 (1 items)