Using Azure Mobile Services in your web apps through ASP.NET Web API

Β· 1493 words Β· 8 minutes to read

Azure Mobile Services is the latest cool thing in town, and if you haven’t checked it out already I really recommend you do, i.e. in this nice introduction post by Scott Gu. In short, it allows you to save/retrieve data in and out of dynamic tables (think no-schema) directly from the cloud. This makes it a perfect data storage solution for mobile apps, but why not use it in other scenarios as well?

For now Azure Mobile Services (a.k.a. ZUMO) is being advertised for Windows 8 only (the SDK is targeted for Windows 8 applications), but there is no reason why you couldn’t use it elsewhere.

Let’s do that and use Web API as a proxy.

Azure Mobile Services πŸ”—

As mentioned, currently, the SDK (Microsoft.WindowsAzure.MobileServices) is Windows 8 only, and while it provides a really rich and fluent API, it’s effectively a wrapper around REST exposed by Azure Mobile Services.

Since that’s the case, we could easily replace that with a RESTful wrapper created with ASP.NET Web API and provide access to our Azure Mobile Services from anywhere - i.e. JavaScript in your web application. You might ask, why not call it directly from JS? Well, we can’t really do that due to cross domain issues. Moreover, saving the data is usually the last step, and in the process you might want to do a whole lot of other stuff, apply all kinds of business logic, to which Web API would have access on the server side.

Setup πŸ”—

The setup is really easy - just go to Azure, and sign up for Azure Mobile Services. It has a 3 month trial.

Then in the Azure Management Portal, choose New > Mobile Service > Create.

You could create a new SQL DB for it, or attach an existing one.

Then all that’s needed is to create a table. You just need a name and permissions, because the schema will be dynamic and dependant on what you save in the the DB.

Now you are good to go.

The model πŸ”—

For the sake of the example, I will use a simple model. Really what we want to do is just to make sure we can do CRUD operations in the ZUMO from the client side (JavaScript), so there is no need to get to fancy.

The model looks like this:

public class Team  
{  
public int? id { get; set; }  
public string Name { get; set; }  
public string League { get; set; }  
}  

We will also see that I don’t need any schema to save/update this type of model in the cloud.

Building the wrapper with Web API πŸ”—

What we really need to do CRUD on this model is a typical Web API REST-oriented controller.

We will expose the following operations:

  1. GET /api/teams/ - get all teams
  2. GET /api/teams/1 - get team by ID
  3. POST /api/teams/ - add a new team
  4. PUT /api/teams/ - update a team
  5. DELETE /api/teams/1 - delete a team by ID
    and then tunnel the request to the Azure Mobile Services.

Access to Azure Mobile Services tables is normally protected with a key so we will have a the controller manage the key (we don’t want the clients doing that). The key needs to be sent with every request to Azure Mobile Services in the headers (alternatively, we could open up the CRUD on the table to anyone, it is possible with the service, but probably not very smart to do).

The skeleton of the controller looks like this:

public class TeamsController : ApiController  
{  
HttpClient client;  
string key = "KEY_HERE";  
public TeamsController()  
{  
client = new HttpClient();  
client.DefaultRequestHeaders.Add("X-ZUMO-APPLICATION",key);  
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));  
}

public IEnumerable<Team> Get()  
{}

public Team Get(int id)  
{}

public void Post(Team team)  
{  
if (ModelState.IsValid)  
{}  
throw new HttpResponseException(HttpStatusCode.BadRequest);  
}

public void Put(Team team)  
{  
if (ModelState.IsValid)  
{}  
throw new HttpResponseException(HttpStatusCode.BadRequest);  
}

public void Delete(int id)  
{}  
}  

We will use the new HttpClient to communicate with the ZUMO RESTful service. We preset the key needed for authenticating us in the X-ZUMO-APPLICATION header key (you get your key from the Azure Management portal, by clicking on the “Manage keys” at the bottom of the page).

Azure Mobile Services exposes data in the following format:

  1. GET https://[your_service].azure-mobile.net/tables/[table_name]/ - get all entries
  2. GET https://[your_service].azure-mobile.net/tables/[table_name]?$filter - get single entry by ID (using OData).
  3. POST https://[your_service].azure-mobile.net/tables/[table_name]/ - add a new entry.
  4. PATCH https://[your_service].azure-mobile.net/tables/[table_name]/1 - update an entry
  5. DELETE https://[your_service].azure-mobile.net/tables/[table_name]/1 - delete an entry by ID

This is almost the same what we have in a standard Web API controller, except by default in Web API projects you’d update with PUT and here you update with PATCH HTTP verb.

Data is submitted and returned via JSON

Get All πŸ”—

public IEnumerable<Team> Get()  
{  
var data = client.GetStringAsync("https://testservice.azure-mobile.net/tables/Teams").Result;  
var teams = JsonConvert.DeserializeObject<IEnumerable<Team>>(data);  
return teams;  
}  

Note, that here I wait for the result of the async operation, which is far from ideal, but it’s fine for a simple demo. I then used JSON.NET to deserialize the results to our POCO.

As expected, we get a nice list of content-negotiated (through Web API) list of NCAA teams.

Get by ID πŸ”—

public Team Get(int id)  
{  
var data = client.GetStringAsync("https://testservice.azure-mobile.net/tables/Teams?$filter=Id eq "+id).Result;  
var team = JsonConvert.DeserializeObject<IEnumerable<Team>>(data);  
return team.FirstOrDefault();  
}  

We use OData on the REST query to ZUMO, to filter by Id column. Again, we use JSON.NEt to deserialize. A small wrinkle is that OData filter will return an array of objects, but since we filter by ID we expect just one so we take the first one.

In this case, just as previously, we get a content negotiated response, this time with Washington State Cougars which we requested for.

Add an item πŸ”—

public void Post(Team team)  
{  
if (ModelState.IsValid)  
{  
var obj = JsonConvert.SerializeObject(team, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore });  
var request = new HttpRequestMessage(HttpMethod.Post, "https://testservice.azure-mobile.net/tables/Teams");  
request.Content = new StringContent(obj, Encoding.UTF8, "application/json");

var data = client.SendAsync(request).Result;

if (!data.IsSuccessStatusCode)  
throw new HttpResponseException(data.StatusCode);  
}

throw new HttpResponseException(HttpStatusCode.BadRequest);  
}  

When we add an item, we will build up the HttpRequestMessage manually; we serialize the POCO to JSON, omit the null values (this is important - since this is a new item it will not have an ID, and a JSON item we submit to ZUMO cannot have an ID property in it, as it would throw a Bad Request error). Then we send the request, and in case it’s not successful we forward the exception down to the client.

We add an item by making a simple POST request. Because we use Web API for forwarding the calls, we could also make this request in XML. In this case we are adding Boise State Broncos from the Mountain West Conference.

Update an item πŸ”—

public void Put(Team team)  
{  
if (ModelState.IsValid)  
{  
var request = new HttpRequestMessage(new HttpMethod("PATCH"), "https://testservice.azure-mobile.net/tables/Teams/"+team.id);  
var obj = JsonConvert.SerializeObject(team);  
request.Content = new StringContent(obj, Encoding.UTF8, "application/json");

var data = client.SendAsync(request).Result;

if (!data.IsSuccessStatusCode)  
throw new HttpResponseException(data.StatusCode);  
}

throw new HttpResponseException(HttpStatusCode.BadRequest);  
}  

This is very similar to POST, except here we use a new HTTP verb, PATCH. Notice it’s not available in the HttpMethod enum so we specify it as a string (which is perfectly fine). We then send the object down to ZUMO.

Updating is a simple PUT. Since Boise St is moving to Big East next year, let’s update their league.

And now Boise is in the Big East.

Delete by id πŸ”—

public void Delete(int id)  
{  
var request = new HttpRequestMessage(HttpMethod.Delete, "https://testservice.azure-mobile.net/tables/Teams/" + id);  
var data = client.SendAsync(request).Result;

if (!data.IsSuccessStatusCode)  
throw new HttpResponseException(data.StatusCode);  
}  

Delete is very simple, just make a DELETE request to the URL with an appropriate ID.

We will delete Kentucky Wildcats, because, well, I don’t like them.

And they are gone.

Summary πŸ”—

We could also view all the data in the Azure management portal - and it’s all as expected (well not all as expected, since Missouri is in the SEC this year but I will not make a new screenshot πŸ™‚ ).

By the way, you might think it’s insane to forward the call via Web API like this - and in the process deserialize from JSON (in Web API) and then serialize again to send down to ZUMO. Yeah, it might sound a bit awkward if you do it straight up like this, but plase remember this is just a simple demo, intended just to show how you could forward the calls back and forth.

In a normal application, in between, you’d probably want to do some stuff with the Models, apply business logic, call different services, process the data and so on - before saving that in the data storage (Azure Mobile Services). Moreover, if you really wish just the basic call forwarding, you could change these Web API signatures to work with JSON object directly, rather than CLR types.

Ultimately, however, it is really easy and convenient to use Azure Mobile Services as a data storage for your app and Web API as a proxy in between, so I recommend you check it out.

About


Hi! I'm Filip W., a cloud architect from ZΓΌrich πŸ‡¨πŸ‡­. I like Toronto Maple Leafs πŸ‡¨πŸ‡¦, Rancid and quantum computing. Oh, and I love the Lowlands 🏴󠁧󠁒󠁳󠁣󠁴󠁿.

You can find me on Github and on Mastodon.

My Introduction to Quantum Computing with Q# and QDK book
Microsoft MVP