Friday, April 6, 2012

ASP.net MVC - Handling json dates with a custom converter.

Handling dates in json can be a real pain as it has no concept of a date datatype - however by using the jQuery ajax() method and specifying a custom converter you can easily turn dates sent from the server into Date objects on the client.

A date when it comes down from the server in json format looks like this:

"BirthDate":"\/Date(1507546800000)\/"

 What is nice about this rather unfriendly format is that is has the /Date prefix (the backslashes are escape chars in json), this means we can look at a string and determine whether we should treat is as a date or not.

I typically use the jQuery ajax() method ($.ajax) to get a json payload from the server. By default if you specify a dataType of 'json' the ajax() method will use an inbuilt converter to turn the returned json string into a javascript object. Fortunately this method also takes a converters object which we can use to parse and transform the json before it is passed to the success() method.

In order for our converter to be called we need to specify a particular datatype - this cannot be one of the default in-built ones or it will be ignored  (such as json) - in this instance I've called mine jsonWithDates. When you specify your converter the first option is a string which says what you're converter is going to take in and return. You need to provide two values in the string separated by a a space (this feels a bit clumsy!). In this case I've specified "text jsonWithDates" because I specified that the dataType I want to deal with is "jsonWithDates" and I want "text" passed into my converter. When the response is received from the server jQuery will look at the converters and see that I have a converter that knows how to do the necessary conversion. Be warned that if you specify "json jsonWithDates" your converter will be passed a javascript object to convert and not a json string as jQuery will do a conversion for you implicitly, that's why I've used "text jsonWithDates".

Ok - so now we know how to hook into the pipeline and set up a converter, that's the hard part done! The second option in the converter object is a function that takes in the payload from the response and provides a converted response. It's up to you now to handle the transformation as you see fit. For my purposes I've used the JSON.parse() method which handily takes in a function that we can use to map individual values when parsing json. In my function I do a check to see if it is a date using a regular expression, if it passes I convert it to a javascript date object and return it.
 
 
Now in my success method I will receive a javascript object that has properties that are of type Date. The full code looks like the following:
 
function LoadDataFromServer() {
        $.ajax({
            url: GetGridURL(),
            type: 'GET',
            dataType: 'jsonWithDates',
            contentType: 'application/json:charset=utf-8',
            //add a custom converter to handle dates and the way 
            //they are sent back from the
            //server in .net
            converters: {
                "text jsonWithDates":
                function (jsonText) {
                    return JSON.parse(jsonText, function (key, value) {
                        // Check for the /Date(x)/ pattern
                        var match = /\/Date\((\d+)\)\//.exec(value);
                        if (match) {
                            var dateIn = new Date(parseInt(value.substr(6)));
                            return dateIn;
                        }
                        // Not a date, so return the original value
                        return value;
                    });
                }
            },
            success:
                function (data) { alert(data);  }
        });
    }
} 
Json date conversion - done!