Get JSON data with jQuery from a .NET service: confused with ajax setup
Asked Answered
P

3

6

I've just spent six hours trying to get this straight in my head and I haven't succeeded.

There's a HelloWorld .NET 3.5 web service on my local machine. Set up as required.
The service returns a List of custom structures.

I'm trying to consume it with jQuery 1.4.4.

When I try to do what the documentation says, I always get back an XML response from the service, which either causes parseerror in jQuery or gets passed as a dumb string to the success function. That is, however I combine dataType and accepts (which, according to the documentation, control how the received data is handled), I get an XML back.

But, when I do something that does not logically follow from the documentation, I successfully get my array of objects. That is, when I ignore dataType and accepts, and set contentType: "application/json; charset=utf-8" instead, it works fine. But contentType, according to the docs, control the data being sent to the server, not received.


In code:

$.ajax(
  {
  type: "GET",
  url: "http://localhost:52624/Service1.asmx/HelloWorld",
  dataType: "json",
  //accepts can be anything, or it can be missing, doesn't matter, only depends on dataType
  success: function(data, textStatus, jqXHR) {...},
  error: function(jqXHR, textStatus, errorThrown) {...}
  }
)

Result: error handler called, textStatus = parseerror.


$.ajax(
  {
  type: "GET",
  url: "http://localhost:52624/Service1.asmx/HelloWorld",
  dataType: "application/json",
  //accepts can be anything, or it can be missing, doesn't matter, only depends on dataType
  success: function(data, textStatus, jqXHR) {...},
  error: function(jqXHR, textStatus, errorThrown) {...}
  }
)

Result: Web service returns XML, it's passed to the success handler as string.


$.ajax(
  {
  type: "GET",
  url: "http://localhost:52624/Service1.asmx/HelloWorld",
  accepts: "json",  // or "application/json"
  success: function(data, textStatus, jqXHR) {...},
  error: function(jqXHR, textStatus, errorThrown) {...}
  }
)

Result: Web service returns XML, it's parsed and passed as IXMLDOMDocument2.


$.ajax(
  {
  type: "GET",
  url: "http://localhost:52624/Service1.asmx/HelloWorld",
  contentType: "application/json; charset=utf-8",
  success: function(data, textStatus, jqXHR) {...},
  error: function(jqXHR, textStatus, errorThrown) {...}
  }
)

Result: Web service returns JSON, which gets partially parsed by jQuery (numbers and strings are parsed into properties of objects, but dates remain in the form of "/Date(1303003305724)/").


Questions:

  1. Do I understand jQuery specs at all? Why is the parameter that is said to control sent data in fact controls received data?
  2. What am I doing blatantly wrong?
  3. What's the last step to get dates parsed by jQuery, too?
Prototype answered 17/4, 2011 at 1:35 Comment(4)
Possible duplicate of Asmx web service how to return JSON and not XML?Honegger
@StephenKennedy That question appeared two years later and, arguably, contains much less material. If anything, you should have voted to close it as a duplicate.Prototype
I'd argue that the newer one gets more directly to the point and is more useful to the casual reader, but I accept this is a judgement call and others may disagree :)Honegger
I've retracted my vote, as this one is more focused on jQuery whereas I'm looking at JavaScriptSerializer stuff today.Honegger
P
2

Looks like I'm going to answer that myself.
I'm not saying the following is the absolute truth. Rather, it is what I have found to be working.


First of all, I found three articles that explained a lot:

In short, the problem with .NET web services is that you have to call them in a special way:

  • Using a POST request (but see below), and
  • Providing Content-Type of application/json; charset=utf-8

This is by design and for security reasons.
The latter may not be avoided, you must provide that content type. And because content type does dictate how parameters are encoded in the request, you must encode your parameters in JSON.

This is where jQuery jumps in. For no reason jQuery would ignore contentType and encode your parameters in application/x-www-form-urlencoded. At which point the web service will dislike you for saying "here is JSON" and providing form-encoded stuff instead.

In these articles, the author recommends that you play a trick with jQuery by enclosing your JSON data in another pair of quotes so that it's interpreted as a string and doesn't get fiddled with by jQuery:

$.ajax({
  type: "POST",
  url: "ServiceName.asmx/WebMethodName",
  data: "{'fname':'dave','lname':'ward'}",
  contentType: "application/json; charset=utf-8",
  dataType: "json",
  success: function(msg) {...}
});

This does work indeed.

Also, if you don't have any data, you still must provide an empty JSON object, {}, because if you don't, jQuery will not set Content-Length, and without Content-Length the web service will dislike you again (more security reasons).


However.
Since FW 3.5, it is possible to use GET with JSON-enabled .NET services. At which point you might wonder how JSON-encoded parameters align with GET requests. Here's how.

If your web service doesn't have any parameters, the call is simple:

$.ajax(
  {
    type: "GET",
    url: "ServiceName.asmx/WebMethodName",
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function(data, textStatus, jqXHR) {...}
  }
);

And if there are parameters, then the call is also simple. What you have to do is provide additional quotes around parameters that should have them! This is because you want these quotes to appear as part of the form-encoded request. This way the form-encoded request will look sort of like json-encoded one:

$.ajax(
  {
    type: "GET",
    url: "ServiceName.asmx/WebMethodName",
    contentType: "application/json; charset=utf-8",
    data: {DatePlaced:'"2011-05-13"'},
    dataType: "json",
    success: function(data, textStatus, jqXHR) {...}
  }
);

This request will result in a request that looks similar to:

GET /ServiceName.asmx/WebMethodName?DatePlaced="2011-05-13" HTTP/1.1
Content-Type: application/json; charset=utf-8

Note the quotes that are required for JSON-like GET requests, but cause an error if you meant to ask for XML.

Prototype answered 16/5, 2011 at 21:44 Comment(0)
S
1

when posting to asp.net web services you always have to set the content type to that - it's their way of preventing json hijacking.

About the dates the easiest solution would be to return the dates as strings dealing date types on the client side will be a huge PITA (from my experience at least).

Stoppage answered 17/4, 2011 at 2:41 Comment(0)
C
1

I think you don't understand the jQuery specs: (Specs)

dataType

Default: Intelligent Guess (xml, json, script, or html)

The type of data that you're expecting back from the server. If none is specified, jQuery will try to infer it based on the MIME type of the response...

Now. Look at your various cases.

Case 1: dataType: "json".

You receive "xml" but declare "json" => you get a parseerror because you can't parse xml as if it was json.

Case 2: dataType: "application/json".

"application/json" is NOT a valid data type, so jQuery defaults to string.

Case 3: No dataType.

jQuery makes its best guess, which turns out fine in your case.

Case 4: contentType: "application/json; charset=utf-8"

You ask for json data, and you don't specify the dataType. In this case you are lucky the Webservice does return json data, and jQuery guesses correctly that the data are in json format.

About the date formating, you want to look at:

How do I format a Microsoft JSON date?

Caz answered 17/4, 2011 at 19:58 Comment(3)
Yes, I realize that. I did think dataType is to request specific data format from the server, and I now realize it's only to tell jQuery what results are going to be. What confuses me is why the only way to instruct the web service to return json (and not xml) is to set contentType, which, according to the documentation, is intended for a different purpose?Prototype
@Greg: That would depend on the webservice, not on jQuery. contentType is not intended for that purpose, but it is part of the message sent to the Webservice. The webservice receives it and decide to do whatever it wants, regardless of its intended purpose in jQuery.Caz
That's GSerg, not Greg, so I didn't get a notification :) Alright then, let me resume. When consuming a .NET web service, you can only get json data if you provide json data in your parameters (because that is what contentType for in the first place -- its json-summoning side effect does not cancel the fact it describes format of parameters sent to the server). So I don't have application/x-www-form-urlencoded any more. But jQuery will handle that somehow. Correct? And, given the scenario, can I use GET at all? I'd think json-encoded parameters require POST.Prototype

© 2022 - 2024 — McMap. All rights reserved.