Experimenting with Windows Azure Mobile Services

The first preview of Windows Azure Mobile Services came out the other week. Over on YouTube, Scott Guthrie gives a great overview of what Mobile Services provides in the preview and on the new Mobile Services site you can get a whole bunch more detail about building with Mobile Services.

At the time, I made a note to set some time aside to look at Mobile Services but I hadn’t quite got around to that when I was down at the Dev4Good hackathon the weekend before last and some of the guys I was working with wanted to try and use these new bits to store their data in the cloud.

I ended up doing a bit of learning with them on the spot and, although I’d seen a few demos, it’s always different when you’re actually sitting in front of the code editor/configuration UIs yourself and someone says “Go on then, set it up” Smile but between us we had something up and running in about 30 minutes which is testament to the productivity of the what Mobile Services does for you.

Beyond the main site, we spent a bit of time reading blog posts from Josh Twist and Carlos Figueira and I’d definitely recommend catching up with what those guys have been writing.

A couple of weeks later, I finally managed to get a bit of downtime to take a look at Mobile Services myself and the rest of this post is a set of rough notes I made as I was poking around and trying to make what I’d read in the quick-starts and on the blogs come to life by experimenting with some code and services myself.

What’s Mobile Services?

The description I’ve got in my head for Mobile Services at this point is something like “Instant Azure Storage & RESTful Data Services” with those services being client agnostic but already offering a specific set of features that make them very attractive as a back end for Windows 8 Store apps such as;

1) Easy integration of the Windows Notification Service for push notifications.

2) Integrated Windows Live authentication so that I can pick up a user’s live ID on the back-end and make authorization decisions around it.

3) Client libraries in place for Windows 8 Store apps written in .NET or JavaScript.

I think the ability to quickly create CRUD-like services over a set of tables and have them exposed over a set of remotely hosted services in a client-agnostic way is a pretty useful thing to be able to do and is likely to save a bunch of boiler-plate effort in hand-cranking your own service to expose and serialize data and get it all set up on Azure (or another cloud service) so I wanted to dive in and dig around a little.

Initial Steps

Once I’d signed up and ticked the right tickboxes for Mobile Services (which took about 3 minutes), I found myself at the dashboard.

image

Where I figured I’d create a new service alongside a new database;

image

image

I’ll delete this service and database server once I’ve written my blog post  and I don’t generally use ‘mtaultySa’ as my user name just in case you were wondering Smile

With that in place, I had a database server and a mobile service sitting somewhere on the other side of the world and navigating into my service showed me that I didn’t have any tables hanging off the service so I figured I’d make one.

image

And I made one called Person because I always make something called Person when confronted with new technology.

image

And that made me a Person table;

image

Which had one column of type bigint (mandatory for a mobile service) to provide me with a primary key but with no data as of yet.

Now, from the quick-starts, I’m aware that a mobile service can have a dynamic schema such that if I send an insert to this table with a column called firstName which can be inferred to be a string then this option;

image

will ensure that my table will ‘magically’ grow a new column called firstName to store that string. However, rather than letting the data define the schema, I felt that I wanted to define my own schema a little to try things out and so instead I went over to the DB tab;

image

And wandered into the table definition and added a couple of new columns;

image

image

And then I saved that and added a couple of rows of data;

image

At this point, I felt that I wanted to be reassured that I could point SQL Management Studio at this database. I’m not sure why but I went off on that side-journey for a moment and made sure I could get a connection string from Azure and connect SQLMS to it once I’d set up the firewall rule to allow my connection to that server;

image

And that all worked fine and I can get to my data from management studio;

image

Although I’m not sure whether the Mobile Services support me in just creating arbitrary columns of any data type this as I think the data-types are [string, numeric, bool, datetime] and I think I also noticed that if I created a table in this DB then it didn’t magically show up in my Mobile Service so I guess there must be a configuration aspect to that somewhere which stores which DB tables are actually part of your service.

From there, I wanted to see my service so I went to its URL;

image

and, sure enough, there’s my service on the web or, at least, a web page that indicates that there’s a sign of life. Not bad for 3-5 minutes of clicking on the web site Smile

Playing Around with Curl and JSON

My first thought was to do something relatively ‘lo-fi’ with this service that didn’t involve a specific type of client or writing code so I figured I would try and extract that data from my service via curl;

 

image

Ok, this wasn’t a rip-roaring success but I’d kind of expected it. There’s a header containing an application key that I think I have to pass across to identify my application. This isn’t really intended to be security as such as I think this would be embedded into the app anyway and relatively easy to sniff but it’s configured via the portal;

image

And leaving the default setting of ‘Anybody with the Application Key’, I went to look up my APPLICATION KEY in my “Manage Access Keys” on the WAMS portal and passed it as a header X-ZUMO-APPLICATION;

image

And that seemed to work just fine and I got some JSON back Smile

[{"id":1,"firstName":"kermit","lastName":"frog"},{"id":2,"firstName":"miss","lastName":"piggy"},{"id":3,"firstName":"fozzie","lastName":"bear"}]

I wanted to try and filter that down a little and as far as I know there’s a query syntax in Mobile Services that is similar to the oData query syntax that I’m pretty familiar with except I think there’s only certain pieces implemented here. I tried a few things like trying equality;

image

Or a greater than;

image

Or maybe a startswith;

image

Or maybe an order by;

image

And perhaps trying out an idea of skipping or taking records (to facilitate paging);

image

Getting a bit brave, I thought I’d try an insert;

image

And my use of CURL is starting to get a bit painful as I escape quote characters and so on but, regardless, I managed to send a new record to my service and I got back the response which included the new ID that was created on the server and I get a 201 back as expected and if I go and visit my service’s data page on the web then I can see that my record (or records because I added a few) are being added;

image

What if I want to add multiple records in one HTTP round-trip? It’s a bit painful with curl but I thought I’d have a try anyway;

image

And that didn’t seem to work – as far as I know, from the forums, that’s not something that’s supported right now.

It also seemed natural to see what happens if I try and insert something that already exists;

image

And that’s pretty clear – given that entities have to have an ID then there’s no way to attempt to insert a duplicate entity this way. I wondered what would happen if I tried to add a unique constraint to the underlying table across firstName, lastName. So, I revisited SQL Management Studio and got rid of my duplicate rows before adding a constraint;

ALTER TABLE [mtaultyFoo].[Person] ADD CONSTRAINT

c_test UNIQUE NONCLUSTERED

(

firstName, lastName

)

And then retrying my previous insert;

image

Which gives me a non-specific error which I can live with just fine as I’m not sure I’d want this error specifically relayed down to the client.

What about updates? Can I change a record? The first thing that I tried was a PUT which gave me an unexpected result;

image

It wasn’t quite what I was expecting and left me wondering how I did an update and then I realised that I was being a little out of date with respect to doing an update via a RESTful service like this and I needed to be using an HTTP PATCH rather than an HTTP PUT.

Keeping up with the times, I had another attempt;

image

Note that the URL has become suffixed with a /1 and that means that the id doesn’t really need to be in the JSON but if it is in the JSON like it is here then it needs to match the URI.

Again, I don’t think that I can do multiple updates in a single batch by passing across an array to the /Person URI.

Again, I can omit the id from the record and still update;

image

Interestingly, I actually messed up that JSON in that I forgot to provide the lastName column name and so consequently, my table just grew a new column called Smith rather than me setting the firstName column to a value of Smith.

That’s one of the risks of having ‘dynamic data’ switched on and having new data properties cause a column to be created!

Having made a bit of a mess, if I want to get rid of a record then I can DELETE rather than PATCH and that works out nicely for me until I use an id that doesn’t exist;

image

And, again, I don’t think that there’s a way of deleting multiple rows with a single HTTP call by default.

That gets me through the whole of CRUD.

What if I wanted to add something typical like a timestamp to my data? I can revisit my table in the portal (or SQL MS) and add a new column;

image

It’s interesting to pull this value back from the service with the current set of data that I have in the table;

image

And so the new modTime column is coming back but the format doesn’t feel quite right. How can I have an effect on that data and its format? I can do this by visiting the read script associated with my Person table on the service. The reference for this server-side scripting is online. I can get rid of modTime by;

image

And then hitting the service now gives me;

image

And so my server-side script has removed that modTime property. If I wanted to use my modTime for something like optimistic concurrency checking then I really need to round-trip it to a client (ideally not allowing for the client to modify it although I’m not sure that I’m going to achieve that here) so I had a stab at getting it as a better formatted value that I could trip down to my client;

image

And then I updated my update function to see if I could test for this ‘rowVersion’ that I was sending down to the client;

image

then it’s possibly a bit clunky but if I initially request my first record;

image

and then I could try and do an update where the data contains the wrong rowVersion number which should fail as below;

image

whereas if I provide the correct rowVersion number;

image

then that works fine.

It’s “interesting” to note that the returned object from my update function is not consistent with the returned object from my read function because the update script on the table doesn’t do the same transformation on the data to turn the database’s modTime column into a value on the JavaScript object called rowVersion. I’d need to replicate that function here if I wanted to reproduce what I had coming back from my read script.

Working with the Client Library

The Azure Mobile Services work really well by just using curl from the command line which means that they can pretty much work from any kind of client that can construct an HTTP request and some JSON content but it’d be nice to get away from command lines and into the client libraries that ship as part of the additional SDK download for Azure Mobile Services;

image

That download gives me bits that I can reference from a .NET Windows 8 App project or a JavaScript one and makes it easy to connect a Windows 8 app to one of these services. I can add a reference in .NET;

image

And then, as is often the case in these kinds of frameworks, there’s a ‘connection like object’ which dishes out other objects that can be used to access specific tables. The ‘connection like object’ is called MobileServiceClient and I can use it as below where it’s operating in an ‘untyped’ manner and just taking URIs and bringing back JSON;

          // Make the 'connection' although nothing goes across the wire
          // at this point.
          MobileServiceClient client = new MobileServiceClient(
            "http://mtaultyFoo.azure-mobile.net",
            "khDwQYiekvuAMQZJQIWUkXFIQvfMFR23");

          // Get the table in an untyped way.
          IMobileServiceTable table = client.GetTable("person");      
    
          // Read some data.
          IJsonValue value = await table.ReadAsync("$filter=(id gt 2)");

          // Do something with the data.
          var stringified = value.Stringify();

and I can perform a similar trick in terms of inserting data in an untyped way;

          // Make the 'connection' although nothing goes across the wire
          // at this point.
          MobileServiceClient client = new MobileServiceClient(
            "http://mtaultyFoo.azure-mobile.net",
            "khDwQYiekvuAMQZJQIWUkXFIQvfMFR23");

          // Get the table in an untyped way.
          IMobileServiceTable table = client.GetTable("person");

          JsonObject jsonData = new JsonObject();
          jsonData["firstName"] = JsonValue.CreateStringValue("Dr");
          jsonData["lastName"] = JsonValue.CreateStringValue("Bunsen");
          IJsonValue value = await table.InsertAsync(jsonData);
          var stringified = value.Stringify();

and I can delete that record;

          // Make the 'connection' although nothing goes across the wire
          // at this point.
          MobileServiceClient client = new MobileServiceClient(
            "http://mtaultyFoo.azure-mobile.net",
            "khDwQYiekvuAMQZJQIWUkXFIQvfMFR23");

          // Get the table in an untyped way.
          IMobileServiceTable table = client.GetTable("person");

          IJsonValue results = await table.ReadAsync("$filter=(lastName eq 'Bunsen')");
          JsonArray array = results.GetArray();

          await table.DeleteAsync(array[0].GetObject());

On the deletion side, I was a bit surprised to find that the call to DeleteAsync actually needed an object rather than just an ID but I guess it allows for more flexibility.

Of course, serializing stuff to/from JSON yourself can get tedious so there’s a higher level API which takes away that sort of pain and uses DataContract serialization to go from a .NET object to a JSON representation and it also uses a LINQ queryable implementation to avoid you having to formulate filters with strings. Going via that route, I can get hold of my data;

      // Make the 'connection' although nothing goes across the wire
      // at this point.
      MobileServiceClient client = new MobileServiceClient(
        "http://mtaultyFoo.azure-mobile.net",
        "khDwQYiekvuAMQZJQIWUkXFIQvfMFR23");

      IMobileServiceTable<Person> table = client.GetTable<Person>();

      MobileServiceTableQuery<Person> query =
        table.Where(p => p.Id > 2).IncludeTotalCount();

      IEnumerable<Person> people = await query.ToEnumerableAsync();

      // How to get to the total count?
      ITotalCountProvider prov = (ITotalCountProvider)people;

      long count = ((ITotalCountProvider)people).TotalCount;

      // do something with the data
      foreach (var person in people)
      {
        // todo
      }

And I can add new data;

      // Make the 'connection' although nothing goes across the wire
      // at this point.
      MobileServiceClient client = new MobileServiceClient(
        "http://mtaultyFoo.azure-mobile.net",
        "khDwQYiekvuAMQZJQIWUkXFIQvfMFR23");

      IMobileServiceTable<Person> table = client.GetTable<Person>();

      Person chef = new Person()
      {
        FirstName = "swedish",
        LastName = "chef"
      };

      await table.InsertAsync(chef);

      // Nice touch, new Id is already populated in the object
      var newId = chef.Id;

and delete data;

      MobileServiceClient client = new MobileServiceClient(
        "http://mtaultyFoo.azure-mobile.net",
        "khDwQYiekvuAMQZJQIWUkXFIQvfMFR23");

      var table = client.GetTable<Person>();

      var results = (await table
          .Where(
            p => p.FirstName == "swedish"
          )
          .ToEnumerableAsync())
          .Single();

      await table.DeleteAsync(results);

and everything is pretty good and pretty easy – what I like about this managed client library is that it’s pretty simple and the calls seem to map onto what I was doing with curl on the command line and it doesn’t seem to attempt to go “too far” in trying to do complex things that I probably won’t need 90% of the time.

What else is in that client side library? From the object explorer in Visual Studio there’s;

image

Authenticating with a Service

So far, I’ve only demanded that the application’s key be provided when a client is interacting with the tables provided by the service. I can go further and require authentication via a Microsoft Account by changing the permissions on the table;

image

and so a query like this one now fails;

     MobileServiceClient client = new MobileServiceClient(
        "http://mtaultyFoo.azure-mobile.net",
        "khDwQYiekvuAMQZJQIWUkXFIQvfMFR23");

      var table = client.GetTable<Person>();

      try
      {
        (await table.ReadAsync()).ToList();
      }
      catch (MobileServiceInvalidOperationException ex)
      {
        // expected
      }

And I need to log in to the service to have a chance of it succeeding – this is married up with Windows Live authentication and so I need to bring in that SDK and make use of it.

image

And then I needed to do a small amount of configuration on my app in order to set it up for Live authentication. That configuration is detailed here;

Get Started with Authentication in Mobile Services

And, for me, essentially involved;

1. Creating a new app at the Store (which I’m going to throw away later).

2. Associating my Visual Studio project with that app (via the Store menu) to get the right package ID and publisher name copied to the manifest.

3. Filling in some basic details at the Live site about the redirect URL for my service.

This process might be slightly different for you if you haven’t yet created a real Store account to do these associations.

With that in play, I can now authenticate with Windows Live and, once again, I can get my data;

       MobileServiceClient client = new MobileServiceClient(
          "http://mtaultyFoo.azure-mobile.net",
          "khDwQYiekvuAMQZJQIWUkXFIQvfMFR23");

        await client.LoginAsync(liveResult.Session.AuthenticationToken);

        // Who is the current user?
        MobileServiceUser user = client.CurrentUser;

        string userId = user.UserId;

        var table = client.GetTable<Person>();

        var data = (await table.ReadAsync()).ToList();

        client.Logout();

and it’s pretty impressive how easy that actually is. If I wanted to get hold of the user in question on the server-side of things then I could modify a script in order to pick it up – e.g. I could tweak my read script on my Person table to include;

image

and that produces a log output that looks something like this (I ‘redacted’ my account number as I’m not sure if it’s ‘secret’ in any way but I guess not);

image

and so now I have authentication working and I can make decisions server-side about what data to serve and/or what operations to allow on that data. Nice Smile

Plugging in Filters

Both the JavaScript and the .NET client side libraries have a concept of filters which look to be a simple plug-in point so that you can hook into the outgoing requests and the incoming responses going to/from your service . On the .NET side, these are represented by IServiceFilter;

 

namespace Microsoft.WindowsAzure.MobileServices
{
  public interface IServiceFilter
  {
    IAsyncOperation<IServiceFilterResponse> Handle(IServiceFilterRequest request, IServiceFilterContinuation continuation);
  }
}

And so if I want to plug in some kind of pre- or post- processing on requests/responses leaving or arriving at my client I can plug in. Here’s one that simply logs a few things;

class DebugTraceFilter : IServiceFilter
  {
    Lazy<Stopwatch> _stopWatch;

    public DebugTraceFilter()
    {
      _stopWatch = new Lazy<Stopwatch>();
    }

    public Windows.Foundation.IAsyncOperation<IServiceFilterResponse> Handle(
      IServiceFilterRequest request, IServiceFilterContinuation continuation)
    {
      _stopWatch.Value.Reset();
      _stopWatch.Value.Start();

      Debug.WriteLine("===");
      Debug.WriteLine("Tracing request made at {0} to URI [{1}]",
        DateTime.Now.TimeOfDay, request.Uri);
      Debug.WriteLine("Verb [{0}]", request.Method);
      Debug.WriteLine("Content type [{0}]", request.ContentType);
      Debug.WriteLine("Accept [{0}]", request.Accept);
      Debug.WriteLine("+++Headers");
      foreach (var item in request.Headers)
      {
        Debug.WriteLine("Header [{0}]=[{1}]", item.Key, item.Value);
      }
      Debug.WriteLine("---Headers");
      Debug.WriteLine("+++Content");
      Debug.WriteLine(request.Content);
      Debug.WriteLine("---Content");

      var response = continuation.Handle(request);

      _stopWatch.Value.Stop();

      // TODO: Write tracing of the response details...

      Debug.WriteLine("Response back at [{0}]", DateTime.Now.TimeOfDay);
      Debug.WriteLine("Elapsed time [{0}]ms", _stopWatch.Value.ElapsedMilliseconds);
      Debug.WriteLine("===");

      return (response);
    }
  }

And I can plug that in;

     LiveAuthClient liveClient = new LiveAuthClient("http://mtaultyFoo.azure-mobile.net");
      LiveLoginResult liveResult = await liveClient.LoginAsync(new string[] { "wl.signin" });

      if (liveResult.Status == LiveConnectSessionStatus.Connected)
      {

        MobileServiceClient client = new MobileServiceClient(
          "http://mtaultyFoo.azure-mobile.net",
          "khDwQYiekvuAMQZJQIWUkXFIQvfMFR23");

        await client.LoginAsync(liveResult.Session.AuthenticationToken);

        // Who is the current user?
        MobileServiceUser user = client.CurrentUser;

        string userId = user.UserId;

        MobileServiceClient filteredClient = client.WithFilter(new DebugTraceFilter());

        var table = filteredClient.GetTable<Person>();

        var data = (await table.ReadAsync()).ToList();

        client.Logout();

      }

And I see output from my tracing code in Visual Studio;

===

Tracing request made at 13:22:27.3903841 to URI [http://mtaultyfoo.azure-mobile.net/tables/Person]

Verb [GET]

Content type []

Accept [application/json]

+++Headers

Header [X-ZUMO-INSTALLATION-ID]=[snip]

Header [X-ZUMO-APPLICATION]=[snip]

Header [X-ZUMO-AUTH]=[snip]

—Headers

+++Content

—Content

Response back at [13:22:27.4117150]

Elapsed time [24]ms

===

Controlling Serialization and Services Without Tables

Most of the rest of the bits in the .NET client library look to relate to controlling JSON serialization and there are already some great blog posts about how that works.

Supporting arbitrary types in Azure Mobile Services managed client – simple types

Supporting arbitrary types in Azure Mobile Services managed client – complex types

Supporting complex types in Azure Mobile Services clients – implementing 1:n table relationships

And that should provide a great head-start in using those classes and that functionality.

Those  posts got me thinking about how I could have a Mobile Service with an endpoint that didn’t directly relate to getting data from a specific table. For example – what if I just want a “get time” endpoint on my service? Can I make that?

As far as I know, scripts need to be associated with a table so in order to have my “get time” service then I’m going to have to create a table, put a ‘read’ script onto it and then hijack the response.

Creating that table;

image

And adding that read script;

image

Seems to have the intended effect although it feels like a bit of a hack.

I tried to take this further. Let’s say that I have two newly defined tables in my schema – Person and Address with very simplified tables;

image

then that immediately gives makes me endpoints for read/insert/update/delete on both of those tables and I could easily write scripts such that on insert/update/delete I ensure the integrity of the relationship between {person:id} and {address:personId} or I could set them up as a proper relationship in SQL and let SQL sort it out even potentially doing things like cascading deletes and so on.

But, what if I want to deal with a joined personAddress entity where I can read back person entities from the database along with their related address entities already joined?

I could change the read script on the person table to do this but then that means that I lose my ability to only return person entities on their own rather than joined to address.

I initially thought that my ‘fake up a table’ approach might work in that I could fake up another new table personAddress with nothing but an id column and no data and then when a read/insert/update/delete operation was performed on personAddress I could try and use the server-side scripts to redirect that work to the underlying person and address tables a little like constructing a view.

However, at the time of writing I don’t quite know how to get that to work in that when I come to that read script I get a bit stuck;

image

And so for the moment I’ve put that idea to one side. I’ll come back to it if I figure it out.

Windows Notification Services

Mobile Services provides an easy way to perform Windows 8 push notifications to a client via the Windows Notification Service rather than me having to build my own cloud service to do it.

This is ‘just’ built into the back-end and is documented up here;

Get Started with Push Notifications in Mobile Services

And, really, it’s a matter of;

1. Making a call on the client to get the channel URI for push notifications.

2. Sending that up to a Mobile Service and probably storing it in a table somewhere.

3. Making a server-side call to an object called push to send the particular type of notification that you want to send.

i.e. it’s made pretty easy with this framework support Smile rather than doing it on your own from scratch. I may revisit this in a subsequent post but the quick-starts are pretty good on it.

Wrapping Up

I learnt a few things about Mobile Services while writing this post and it was fun to experiment and poke around. I think this is going to prove to be a very popular way of getting a cloud-based back-end up and running without spending days trying to build with WCF and get your service configured and so on. Sometimes that’s necessary but for simple services Mobile Services is going to be a big win.

I have a few things that I want to figure out that I wrote down while I was going along;

1. While the logging support is pretty decent, I’d prefer to use a client side logging tool – I could see someone (me?) writing a simple tool which did logTable.log() and then there was a Windows client to poll that log table every few seconds and display the output.

2. I’d like to figure out whether I can have a service which doesn’t directly access a specific table but can still take parameters from the query string.

3. I’d like to be able to do multiple inserts/updates/deletes on a single HTTP request.

5. I’d be curious to know whether it’s possible to re-use pieces of script code across server-side scripts to get some re-use without duplicating the code.

6. It’d be good to look at client-side caching and/or synchronisation and how that might be made to work.

And I daresay there’s a bunch more to figure out but I’ll push that to future posts as this one has got way too long Smile