Azure + Bing Maps: Accessing OData Services from AJAX Clients

This is the 9th article in our "Bring the clouds together: Azure + Bing Maps"
series. You can find a preview of live demonstration on

https://sqlazurebingmap.cloudapp.net/. For a list of articles in the series,
please refer to https://blogs.msdn.com/b/windows-azure-support/archive/2010/08/11/bring-the-clouds-together-azure-bing-maps.aspx.


Introduction

The
last post focused on the client side. We described how to display
structured data with the help of jQuery Templates.

This post will combine the client with

the cloud WCF Data Services we built earlier. After complete reading
this post, you'll be able to consume an OData service (such as WCF Data
Services) from an AJAX client.


OData clients overview

OData is an open protocol that is
based on HTTP standard. So any clients that supports HTTP are able to
consume the service. No matter what client library you're using, under
the hook, you're always issuing HTTP requests like GET and POST. OData
is used by a lot of Microsoft products, including Windows Azure Table
Storage. OData supports common data formats such as ATOM and JSON. So
you can use your existing knowledge to parse the data returned from the
service (note certain services like table storage only supports a subset
of the protocol).


Browser clients

The simplest way to access an OData service is to use your browser. In
our sample, when testing against Development Fabric, you can open your
browser and navigate to

https://127.0.0.1:81/DataService/TravelDataService.svc/Travels. Then
view source of the page. This will list all entities in the ATOM format.

You can also request a single entity by appending the key in the
request. If your entity's key is a simple integer, you can use URI like
https://host/yourservice.svc/YourEntitySet(21). This will return the
entity whose ID is 21. In our sample, since the entity key contains two
properties, we need to put both of them in the URI. For example:

https://127.0.0.1:81/DataService/TravelDataService.svc/Travels(PartitionKey='testuser',RowKey=guid'783323a1-b1f1-4910-b5be-a2f37e62d0ba').

Additionally, you can perform common tasks such as filtering, sorting,
and paging. We will not go into the details in this post. You can find
the complete documentation on

https://www.odata.org/developers/protocols/uri-conventions.


Fiddler client

Browser allows you to test GET operations using ATOM format. To use the
JSON format, or to test other verbs like POST, you can take advantage of
Fiddler. For example, to update an entity in our sample, you can use
Fiddler's Request Builder feature to issue a PUT request. You can also
specify the Content-Type as "application/json; charset=utf-8", so you
can use the JSON format with UTF-8 encoding.

Fiddler Request Builder


Other clients

To consume OData services in your client application, you can either
issue HTTP requests directly, or use a client library listed on

https://www.odata.org/developers/odata-sdk. The client library for
.NET/Silverlight is already built into .NET Framework/Silverlight SDK.
The next section will focus on accessing OData services from AJAX
clients. We assume most Azure developers already know how to use the
.NET/Silverlight client library since this is the same library used to
access table storage. So we'll briefly cover it in a future post when
working with a Silverlight client.

Working with OData Services from AJAX clients

You can find an OData JavaScript client library on

https://www.odata.org/developers/odata-sdk. Using this library is
straightforward if you're working on ASP.NET AJAX. The syntax is exactly the
same as ASP.NET AJAX. You can find a detailed tutorial on

https://www.asp.net/ajaxLibrary/odata.ashx. So we will not repeat in this
post.

Instead, we'll describe how to accessing OData services using jQuery. This
approach requires slightly more code compared to using ASP.NET AJAX library. But
it allows you to see the underlying HTTP requests. The basic idea is of course
using the ajax function.
We'll use the JSON format for all requests.

Query

To query a data service, you issue GET requests, as you do in the browser.
For example, to query all entities created by a user (PartitionKey) ordered by
time, you can use the following code:

$.ajax(

{

type:
'GET',

url: dataServiceUri +
'/Travels?$filter=PartitionKey eq
'TestUser'&$orderby=Time',

dataType:
'json',

success:
LoadDataCompleted,

error:
function () {

$('#ErrorInforamtion').text('Error
retrieving data. Please try again later.');

}

});

In the LoadDataCompleted callback function, you can parse the result JSON
data,

display them in the list, and

add pushpins on the map. Please refer to our previous posts on how to do
that.

Update

To update an entity, you issue a PUT request. You need to specify the keys in
the URI, so the service is able to find the entity to update. You've already
seen a sample of the request body in the above screenshot. Note the request body
looks exactly like a JSON object. To construct the request body, you can either
manually construct a string, or as recommended by the JSON group, use
JSON stringify to serialize a JSON
object to a string.

$.ajax(

{

type: 'PUT',

url: dataServiceUri + "/Travels(PartitionKey='"
+ this.PartitionKey +
"',RowKey=guid'" + this.RowKey +
"')",

contentType: 'application/json; charset=utf-8',

data: JSON.stringify(item.Value),

datatype: 'json',

error: function () {

$('#ErrorInforamtion').text('Error
retrieving data. Please try again later.');

}

});

Insert

To insert a new entity, you issue a POST request. The request body is
identical to PUT. So the only differences are the HTTP verb and the URI. You
don't need to specify the keys in URI, since the entity doesn't exist yet.

$.ajax(

{

type: 'POST',

url: dataServiceUri + '/Travels',

contentType: 'application/json; charset=utf-8',

data: JSON.stringify(item.Value),

datatype: 'json',

error:
function () {

$('#ErrorInforamtion').text('Error
retrieving data. Please try again later.');

}

});

Delete

Finally to delete an entity, of course issue a DELETE request. You also need
to specify the keys in the URI. DELETE requests do not contain request bodies.

$.ajax(

{

type: 'DELETE',

url: dataServiceUri + "/Travels(PartitionKey='"
+ this.PartitionKey +
"',RowKey=guid'" + this.RowKey +
"')",

contentType: 'application/json; charset=utf-8',

datatype: 'json',

error: function () {

$('#ErrorInforamtion').text('Error
retrieving data. Please try again later.');

}

});

Track entity states

When working with .NET/Silverlight clients, the OData client libraries take
care of entity state tracking for you. This means you can insert/update/delete
an entity to a list in the client's memory. Then you can either discard the
modification, or invoke the SaveChanges method to make all requests to the
server. This is a useful feature. Unfortunately it is not supported out of box
by AJAX clients. So you have to manually track the entity states. You can do so
by adding modified items to arrays. We won't go into the details in this post.
But we have a sample implementation in our source code, which will be released
later.

Conclusion

This post described how to access OData Services from AJAX clients. At this
point, our HTML client is almost feature complete, and we're able to connect it
to our cloud service. The next post will describe how to integrate federated
authentication to your applications.