JQuery, JSON, and the REST Starter Kit

7 05 2009

The new version of Zleek will be retrieving all of its data from a RESTful WCF Service that serves up JSON data. It also makes heavy use of the JQuery 1.3 libraries with the JQuery JSON 1.3 plugin. Are they interoperable?

If you’ve worked with the REST Starter Kit on the server and JQuery on the client, you probably already know the answer: almost.

The problem lies in date serialization. Say you have the date 5/6/2009 and you want to pass it to your RESTful WCF service as JSON. Here is how JQuery serializes it:

“2009-06-05”

And here is how the MicrosoftAjax.js library serializes it:

“”\/Date(1246777200000)\/””

Your WCF service will only be able to deserialize dates in the Microsoft format and will throw an exception otherwise. You will also have the same problem going the other way. If your WCF service returns a DateTime object, it will be deserialized by JQuery as a string. Luckily, due to the nature of JSON (de)serialization, both of these issues are easy problems to fix.

I only wish I had seen Rick Strahl’s excellent posts from a year ago on this issue prior to tackling it. Apparently I’m Google-inept…

Situation 1: Transmitting dates from a JQuery client to a WCF service

For those of you new to JavaScript development, JavaScript is a dynamically typed language. Your prototype object can have a date property that you can change to a string or a number at any time without any issues. This property of JavaScript can be leveraged to fix our problem.

Prior to calling the JQuery library and issuing the request to the WCF service, you can change it to a string that will be serialized like the way MicrosoftAjax serializes dates. To get an output of:

“”\/Date(1246777200000)\/””

We need an input of:

“/Date(1246777200000)/”

Here is a function you can use to do just that. It takes a JavaScript Date object and turns it into a string that JQuery will then serialize into the MicrosoftAjax date serialization format.

   1: Agnition.Serialization.SerializeDate = function(date) {

   2:     /// <summary>

   3:     ///    JQuery cannot serialize a Date object so that .NET can read it, this fixes its attempt by calling

   4:     ///    the MS AJAX serializer. JQuery will then serialize a string correctly.

   5:     /// </summary>

   6:     /// <param name="date">The date to serialize</param>

   7:     /// <returns>A JSON serialized date formatted for .NET</returns>

   8:     var dateString = Sys.Serialization.JavaScriptSerializer.serialize(date);

   9:     dateString = dateString.substring(2);

  10:     dateString = dateString.substring(0, dateString.length - 3) + "\/";

  11:     return dateString;

  12: };

Here is an example of it in use:

   1: this.CreateBook = function(successCallback, errorCallback) {

   2:     /// <summary>Attempts to register the user</summary>

   3:     /// <param name="successCallback">The callback fired if the request is successful</param>

   4:     /// <param name="errorCallback">The callback fired if the request failed</param>

   5:  

   6:     var albumData = this.AlbumData;

   7:     var svcAddress = this.ServiceAddress;

   8:  

   9:     albumData.LastUpdated = Agnition.Serialization.SerializeDate(albumData.LastUpdated);

  10:     var jsonRequest = new Agnition.Net.WebRequest();

  11:     var url = svcAddress + "/Album/new?includeMedia=false";

  12:     jsonRequest.PutJson(url, albumData, successCallback, errorCallback, null);

  13: };

Situation 2: Receiving dates from a WCF service in a JQuery client

This issue is basically the reverse of Situation 1. Your WCF service will serialize a DateTime object in the MicrosoftAjax format. JQuery will see this and deserialize it as a string. All we have to do is modify this string to put it back into the MicrosoftAjax format, and then use the MicrosoftAjax library to deserialize it. Here is what JQuery will deserialize the response as (notice it’s a string):

“/Date(1240902876467-0700)/”

Here is a function that will perform the translation for you:

   1: Agnition.Serialization.FixJQueryDate = function(dateString) {

   2:     /// <summary>

   3:     ///    JQuery cannot deserialize the .NET dateTime object, so this fixes its attempt by reconstructing

   4:     ///    the string and calling the MS AJAX deserializer.

   5:     /// </summary>

   6:     /// <param name="dateString">The JQuery deserialized date string</param>

   7:     /// <returns>A JavaScript date object</returns>

   8:     dateString = dateString.substring(1);

   9:     dateString = dateString.substring(0, dateString.indexOf("\/"));

  10:     dateString = "\"\\\/" + dateString + "\\\/\"";

  11:     var date = Sys.Serialization.JavaScriptSerializer.deserialize(dateString);

  12:     return date;

  13: };

And here is an example of it in use:

   1: $(document).ready(function() {

   2:     var request = new Agnition.Zleek.Web.Service.PagedDataRequest(bookUrl, BOOK_PAGE_SIZE, BOOK_MAX_RECORDS);

   3:     request.GetPage(BOOK_CURRENT_PAGE,

   4:             function(data, statusText) {

   5:             /* snip */

   6:                 for (var i = 0; i < numAlbums; i++) {

   7:                     var album = data.Albums[i];

   8:                     album.LastUpdated = Agnition.Serialization.FixJQueryDate(album.LastUpdated);

   9:             /* snip */

  10: };

Now, assuming all of the dates in our service are UTC dates, this function will perform the conversion from UTC to the browser’s local time, and then we can create a new method which fixes both the date serialization and performs the time conversion:

   1: Agnition.ConvertUTCToLocalTime = function(date) {

   2:     /// <summary>Converts a UTC date to local time</summary>

   3:     /// <param name="date">The date object to convert</param>

   4:     /// <returns>The resulting local time</return>

   5:     var utcTime = date.getTime();

   6:     var localOffset = date.getTimezoneOffset() * 60000; // Get offset in milliseconds

   7:     var localTime = utcTime - localOffset;

   8:     return new Date(localTime);

   9: };

  10:  

  11: Agnition.Serialization.GetJQueryDateAsLocalTime = function(dateString) {

  12:     /// <summary>

  13:     ///    JQuery cannot deserialize the .NET dateTime object, so this fixes its attempt by reconstructing

  14:     ///    the string and calling the MS AJAX deserializer. The resulting date is then converted to local

  15:     ///    time from UTC time.

  16:     /// </summary>

  17:     /// <param name="dateString">The JQuery deserialized date string</param>

  18:     /// <returns>A JavaScript date object, converted from UTC to local time</returns>

  19:     return Agnition.ConvertUTCToLocalTime(Agnition.Serialization.FixJQueryDate(dateString));

  20: };

Caveat Emptor

Because there is no standard date literal in JavaScript, Microsoft AJAX and JQuery may change their respective JSON date serialization formats in the future. So if you’re using this solution (and hopefully created a single function to perform the translations), you may have to modify your translation code when using future releases of JQuery or MS AJAX. In fact, Microsoft has already changed their format once before, and may do so again in the future.

Advertisements

Actions

Information

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: