Days ago I blogged about how to call a WCF service from a jQuery application to retrieve and send data to the server to realize a small interactive chatting application. Everything was working fine until it came to format any DateTime data passed from the server to the client.

We ended up having a call like this:

var msg3 = { "msg": { "Id": "2", "Sender": "Webpage", "Text": "Sended Text" }, "id": "1" };
 
$(document).ready(function() {
    $.ajax({
        type: "POST",
        url: serviceUrl + "TestMessageModifyWithSuppliedContent",
        // data: "{ \"msg\" : " + JSON.stringify(msg) + ", \"id\" : \"4\"}",
        data: JSON.stringify(msg3),
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function(data) {
            //debugger;
            var text = data.d.Timestamp + " - " + data.d.Sender + " - " + data.d.Text;
            alert(text);
        },
        error: function(XMLHttpRequest, textStatus, errorThrown) {
            debugger;
            alert("Error Occured!");
        }
    });
});

the output of this code is a Message Box with the following text:

"/Date(1267695086938+0100)/ - Webpage - 3 - Second parameter passed: 1"

Looking at fiddler for the request and the response we have:

POST http://localhost.:58817/Services/ChatService.svc/TestMessageModifyWithSuppliedContent HTTP/1.1
...Request plumbing goes here...
Pragma: no-cache
 
{"msg":{"Id":"2","Sender":"Webpage","Text":"Sended Text"},"id":"1"}
HTTP/1.1 200 OK
...Response plumbing goes here...
Content-Type: application/json; charset=utf-8
Content-Length: 160
Connection: Close
 
{"d":{"__type":"Message:#LiveAssistance.Entities","Id":2,"Sender":"Webpage","Text":"3 - Second parameter passed: 1","Timestamp":"\/Date(1267694873788+0100)\/"}}

I was surprised at fist, then a quick research show that this is the way WCF serializes the DateTime object in JSON. In short the first number represent the number of milliseconds in the GMT time zone, regular (non-daylight savings) time since midnight, January 1, 1970. The number may be negative to represent earlier times. The second is the time zone (more info here: Stand-Alone JSON Serialization).

So we have to do something to convert this string representation in a JavaScript Date() object. To do so we can use the ‘dataFilter’ feature of the jQuery ajax() call that allows us to modify and alter the returned JSON string representation before it’s passed on to the parser.

We basically want to change the string “/Date(1267695086938+0100)/” to
“new Date(Date(1267695086938+0100)”; to do so we can rewrite our ajax call like this:

   1: $(document).ready(function() {
   2:         $.ajax({
   3:             type: "POST",
   4:             url: serviceUrl + "TestMessageModifyWithSuppliedContent",
   5:             // data: "{ \"msg\" : " + JSON.stringify(msg) + ", \"id\" : \"4\"}",
   6:             data: JSON.stringify(msg3),
   7:             contentType: "application/json; charset=utf-8",
   8:             dataType: "json",
   9:             dataFilter: function(data, type) {
  10:                 var d = data.replace(/"\\\/(Date\(.*?\))\\\/"/gi, 'new $1');
  11:                 return d;
  12:             },
  13:             success: function(data) {
  14:                 //debugger;
  15:             var text = data.d.Timestamp.format("yyyy/mm/dd - HH:MM:ss") + " - " + data.d.Sender + " - " + data.d.Text;
  16:                 alert(text);
  17:             },
  18:             error: function(XMLHttpRequest, textStatus, errorThrown) {
  19:                 debugger;
  20:                 alert("Error Occured!");
  21:             }
  22:         });
  23:     });

Lines 9 - 12 shows our filtering function with the Regex we use to convert the returned JSON string representation to this one:

FROM:
 
"{"d":{"__type":"Message:#Entities","Id":2,"Sender":"Webpage","Text":"3 - Second parameter passed: 1","Timestamp":"\/Date(1267696301237+0100)\/"}}"
 
TO:
 
"{"d":{"__type":"Message:#Entities","Id":2,"Sender":"Webpage","Text":"3 - Second parameter passed: 1","Timestamp":new Date(1267696301237+0100)}}"

Everthing is now working and the Timestamp field contains a Date object...if you use jQuery 1.3.x...

If (like me) you use jQuery 1.4.x you will get an error from the JSON serializer with an ‘invalid JSON format’ message...and guess...he’s right because “new Date(something)” isn’t a valid representation...so why the hell it all worked before?

It turned out that jQuery 1.3.x used the JavaScript eval() function to internally deserialize objects (so using the method above we used in reality a trick), jQuery 1.4.x relies on the browser capabilities to deserialize JSON streams (in particular it uses the window.JSON object if the browser has support for it).

It does this way mainly for performances and security reasons. So we have 2 ways now to get a Date object from our string representation:

1- process each object with a function that (using the previously pointed regex and the eval() function) convert each date field to the corresponding object.

2- change the way the data are parsed (client-side) and do our own JSON deserialization using eval(), to act this way we need to change the ‘dataType’ returned from ‘json’ to ‘text’ - this way we disable the automatic deserialization - then we have to call the eval() function on the returned and modified data stream:

   1: $(document).ready(function() {
   2:         $.ajax({
   3:             type: "POST",
   4:             url: serviceUrl + "TestMessageModifyWithSuppliedContent",
   5:             // data: "{ \"msg\" : " + JSON.stringify(msg) + ", \"id\" : \"4\"}",
   6:             data: JSON.stringify(msg3),
   7:             contentType: "application/json; charset=utf-8",
   8:             dataType: "text",
   9:             dataFilter: function(data, type) {
  10:                 var d = data.replace(/"\\\/(Date\(.*?\))\\\/"/gi, 'new $1');
  11:                 return d;
  12:             },
  13:             success: function(data) {
  14:                 //debugger;
  15:                 data = eval('(' + data + ')');
  16:                 var text = data.d.Timestamp.format("yyyy/mm/dd - HH:MM:ss") + " - " + data.d.Sender + " - " + data.d.Text;
  17:                 alert(text);
  18:             },
  19:             error: function(XMLHttpRequest, textStatus, errorThrown) {
  20:                 debugger;
  21:                 alert("Error Occured!");
  22:             }
  23:         });
  24:     });

Lines 8, 15 and 16 shows the modifications we made. As you can see in line 16 now you can use the Timestamp field as a data object and format it using any JavaScript DateTime formatting library you like.

As a note: using this second method you are obviously loosing in performance and security, cause eval() is slower than the native JSON deserialization, and even worse you are subject to code injection attacks.

Related Content