Using jQuery with ASP.NET Web Services and JSON
Posted April 7, 2009 by Chris | Filed under ASP.NET, Ajax, jQuery
By now, hopefully everyone's played with jQuery for client-side JavaScript work and knows it eliminates the fuss of manually writing Ajax code. In this post, I'll briefly cover the idiosyncrasies of using jQuery Ajax to consume .NET 3.5 web services that serve JSON. Although I mostly show examples of ASPX pages with WebMethods, all the JavaScript herein applies to JSON-enabled ASMX and WCF services as well. In the next post, I'll introduce a simple script that makes all this even easier, burying these semantics so you can forget everything you read in this one.
If you'd just like to learn by seeing a working example of jQuery and service methods (in ASPX pages) without, look at the end of this post.
Sending a Request
If you've used jQuery to work with ASP.NET web services using JSON, you've probably learned the boilerplate code below. If you haven't, this is how to send a JSON request (to the page msg.aspx serving the method GetLast(), in this illustration):
$.ajax({ type: "POST", url: "msg.aspx/GetLast", data: "{}", contentType: "application/json; charset=utf-8", dataType: "json", success: getLastSuccess, error: getLastError });
Let's get this out of the way first: type is always "POST".
Now, if the request is bad (e.g. a GET, non-existent service method) and is to a method defined in the class of an ASPX page, $.ajax() will fire the error function, passing the XHR object as the first argument to error. The responseText of the XHR will contain the HTML of the ASPX page. This is because ASP.NET will serve the page when the request to the service method is rejected, and responseText is the body of the HTTP response.
// A BAD REQUEST WITH "GET" $.ajax({ type: "GET", url: "msg.aspx/GetLast", data: "{}", contentType: "application/json; charset=utf-8", dataType: "json", success: getLastSuccess, error: function(xhr) { // alert()s the HTML of msg.aspx alert(xhr.responseText); } });
If the request is fine, but an exception goes unhandled in the service, the error function will fire as well, and the responseText will be the exception serialized to JSON. It will only include the Message, StackTrace, and ExceptionType members, however.
Sending Arguments to Service Methods
In the $.ajax() options used to send a request,
To send arguments to a service, create an object whose member names match the argument names of the service method. For example, say we've got this method:
[WebMethod] public static void PostMessage (DateTime timestamp, string author, string message) { ... }
Construct an object to send to the service method parameters as shown below. This object will be serialized to JSON and sent as the
var message = { timestamp: new Date(), author: "Chris", message: "Tag! You're it." };
Once we have an object whose members match the ASP.NET method's arguments, it needs to be serialized into a JSON string. Be safe, use a script that does it for you, like this one. Call that script's JSON.stringifiy(object) to serialize the
$.ajax({ type: "POST", url: "msg.aspx/PostMessage", data: JSON.stringify(message), contentType: "application/json; charset=utf-8", dataType: "json", success: function() { alert("Message posted"); } });
Receiving Data Back
If the request is responded to successfully, the success function in the $.ajax() options is called. If the service method has a return value,
The object will have one and only one member, named "
[WebMethod] public static string GetLast() { return "foobar"; }
jQuery creates an object out of this JSON after receiving it. The string "foobar" is retrieved by accessing
$.ajax({ type: "POST", url: "msg.aspx/GetLast", data: "{}", contentType: "application/json; charset=utf-8", dataType: "json", success: function(data) { var result = data.d; // result == "foobar" } });
What happens if the type returned by a service method is a complex type (e.g. a class)? Let's take a look. Here's a class and service method that returns it:
public class Person { public int Age; public string Name; public bool Male; } public partial class _Default : Page { [WebMethod] public static Person GetChris() { return new Person() { Age = 120, Name = "Chris", Male = true }; // serializes to: // {"d":{"__type":"Person","Age":120,"Name":"Chris","Male":true}} } }
When the GetChris() is result is received, it's a JavaScript object whose member names match the field names of the Person class, with an additional member named "
$.ajax({ type: "POST", url: "Default.aspx/GetChris", data: "{}", contentType: "application/json; charset=utf-8", dataType: "json", success: function(data) { var result = data.d; var type = result.__type; // == "Person" (String) var name = result.Name; // == "Chris" (String) var age = result.Age; // == 120 (Number) var male = result.Male; // == true (Boolean) debugger; } });
Dealing with Dates
Primitives and classes are simple to deal with. Their conversions are out-of-the-box. There's one that's a little trickier: .NET DateTime objects. When a service serializes a DateTime object, it comes back as a specially-formatted string. Consider this method:
[WebMethod] public static DateTime WhatTimeIsIt() { return DateTime.Now.ToUniversalTime(); }
.NET serializes this response to
$.ajax({ ... url: "time.asmx/WhatTimeIsIt", success: function(data) { var time = data.d; // time == "/Date(1238800185359)/" } });
The numbers in the JSON string are a unix time, but in ms instead of seconds. This is the amount of time that has elasped between Jan. 1, 1970 at midnight UTC and the date the DateTime object represents. If the number is negative, it is before the 1970 epoch.
Parsing it in JavaScript and creating a Date object out of it isn't difficult to accomplish using Regular Expressions though:
function jsonParseDate(obj) { if (typeof obj !== "string") { return obj; } var match = obj.match(/^\/Date\((-?\d+)\)\/$/); if (!match) { return obj; } return new Date(parseInt(match[1])); }; $.ajax({ type: "POST", url: "time.asmx/WhatTimeIsIt", data: "{}", contentType: "application/json; charset=utf-8", dataType: "json", success: function(data) { // data.d is a string = "/Date(1238800185359)/" var time = jsonParseDate(data.d); // time is now a Date object // alert()s "Friday, April 03, 2009 4:09:45 PM" alert(time.toLocaleString()); } });
If
function dateFix(obj) { if (obj === null) { return obj; } // ASP.NET JSON date? if (typeof obj === "string") { var match = obj.match(/^\/Date\((-?\d+)\)\/$/); // nope, regular string if (!match) { return obj; } // yup, JSON-serialized DateTime return new Date(parseInt(match[1])); } // string or number if (typeof obj !== "object") { return obj; } // array or object jQuery.each(obj, function(key, val) { obj[key] = dateFix(val); }); return obj; } $.ajax({ type: "POST", url: "blog.asmx/GetLastPost", data: "{}", contentType: "application/json; charset=utf-8", dataType: "json", success: function(data) { data = dateFix(data); // any strings for JSON dates are now JavaScript Date objects } });
Example Code, Next Post
You can download a working example of this code here. There's not a whole lot to it, but if you're like me, there's enough quirks and repetition to do something about it. In the
Tags: Ajax, ASP.NET, ASP.NET AJAX, JavaScript, jQuery, JSON, JSON dates, parse JSON dates, web services
April 8th, 2009 at 2:03 am
[...] my last post, I gave a quick introduction to using jQuery for JSON communication with ASP.NET web and WCF [...]
May 19th, 2009 at 8:33 am
You would not believe how many sites I had to plow through before I find an actual explanation on the breakdown of the syntax! Thank you so much!
May 29th, 2009 at 2:43 am
@Chris,
Glad I could help! If you have any suggestions that could help me streamline the entry so that people get to the meat sooner, let me know! Take care, Chris.
June 27th, 2009 at 12:14 am
Great tutorial, it is the exact architecture we just selected.
You save some proof of concepting time.
October 12th, 2009 at 6:01 pm
Ваш проект полезен для людей в теме. Давно отслеживаю за вашим развитием проекта с каждым днем всё лучше. Спасибо за топик. Обязательно у себя в блоге ссылку про пост оставлю. Инфа реально качественная
November 12th, 2009 at 11:05 pm
Glad I could help!
November 15th, 2009 at 2:47 am
Good Article but still one thing is missing how I can Pass Object From Json and accept object from webMethod. You have provided example of passing object but i have to recieve each value as sepereate not as object in webMethod
For example
Public Shared Function RegisterMemberObject(ByVal FirstName As String, ByVal LastName As String, ByVal Email As String) As Register
End Function
Not
Public Shared Function RegisterMembertest(ByVal objRegister As Register) As Register
End Function
December 20th, 2009 at 11:58 pm
how we call a webservice using json?
January 13th, 2010 at 12:27 am
Hi great article………………thanks very much.
If i want to obtain the return values from web method. how to obtain from response.d please reply
February 16th, 2010 at 4:40 am
Nice article.. Its Very useful for me..
Thanks
February 16th, 2010 at 8:25 am
I see how you passed a date to a page. Can you show how you pass an XMLDOM to a aspnet web service? I can do it using the old MS behaviors (HTC), but I cannot get this done with JQuery. I’m sure it is possible. Thanks.
March 3rd, 2010 at 12:35 am
As per above example, if my JSON response of type List then how i can handle this response in jquery.
March 3rd, 2010 at 2:56 am
Thanks! I got the solution.