ajax解析properties,AJAX result.d实例解释
When working directly with JSON serialized ASMX services, be it
via jQuery, pure XmlHttpRequest calls, or anything else other
than the ScriptManager, one question inevitably arises. That
question is of the inexplicable .d attribute that
appeared in ASP.NET 3.5.
What is it? Why is it there?
In this post, I’ll use both a 2.0 and a 3.5 example ASMX web
service to illustrate exactly what’s going on.
I’ll also show you why it’s a good change.
An example
Following a concrete example always helps to better clarify
these things. For that purpose, let’s assume that we want to call a
web service and retrieve an instance of the following
Person class:
public class Person
{
public string FirstName;
public string LastName;
}
The ASMX web service to return an instance of that class could
be simple as this:
[ScriptService]
public class PersonService : WebService
{
[WebMethod]
public Person GetPerson()
{
Person p = new Person();
p.FirstName = "Dave";
p.LastName = "Ward";
return p;
}
}
Because our WebService class is decorated with the
[ScriptService] attribute, the ASP.NET AJAX Extensions
(System.Web.Extensions) will automatically serialize the return value as JSON if properly
requested.
Note: A common anti-pattern that I’ve seen in
practice is using a return type of string and returning a manually
JSON serialized object. Don’t. It’s unnecessary and results in
doubled effort on both the server and in the browser.
Let the framework handle this task unless you have a good reason
not to use the built-in functionality. It works just fine in most
scenarios.
Calling the service and inspecting its result
Using jQuery to consume an ASMX web service is simple, but does
require jumping through a few hoops. We can use this jQuery to consume
the Person service we just created:
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "PersonService.asmx/GetPerson",
data: "{}",
dataType: "json",
success: function(msg) {
// Do interesting things here.
}
});
Making that call against an ASP.NET 2.0 site with the ASP.NET
AJAX Extensions 1.0 installed, this JSON object would be the return
value:
I find that it often helps to visualize the JSON in a more human
readable format. This is the same JSON object as seen in the
Firebug screenshot above:
{"__type" : "Person",
"FirstName" : "Dave",
"LastName" : "Ward"}
Within the success callback shown above, you
may access properties of the Person exactly as you would expect.
For example, msg.FirstName will evaluate to
“Dave”.
Waiter, there’s a .d in my msg soup!
Eventually, you’ll finally convince management to let
you upgrade the site to ASP.NET 3.5. After all, you can use an
object initializer to cut the size of the web service in half!
However, your msg.FirstName statement now results in the
dreaded undefined.
What happened? Let’s inspect the ASP.NET 3.5 response in
Firebug:
The entire Person object is wrapped within a new
“d” object now. Alternatively we might visualize
it this way:
{"d":{"__type" : "Person",
"FirstName" : "Dave",
"LastName" : "Ward"}}
As you’ve probably figured out by now, the solution is to
reference the property as msg.d.FirstName now. In
our example, this will again resolve correctly as “Dave”.
This is the case with all ASMX services JSON
serialized through the ASP.NET AJAX Extensions in ASP.NET 3.5. Even
if you’re only returning a scalar return value, such as a string,
int, or boolean, the result will always be enclosed within the
“d”.
Why did it change?
While I wish this unexpected change had been more clearly
announced, it’s a good one. Here’s how Dave Reed explained it
to me:
{"d": 1 }
Is not a valid JavaScript statement, where as this:
[1]
Is.
So the wrapping of the "d" parameter prevents direct execution
of the string as script. No Object or Array constructor
worries.
[] is JavaScript’s array literal notation, allowing you to
instantiate an array without explicitly calling a constructor. To
expand on Dave’s explanation, simply consider this code:
["Dave", alert("Do Evil"), "Ward"]
That literal array declaration will execute the
alert in most browsers. Danger!
Update: For an even better description of why
the .d is important, from Dave Reed himself, be sure to see
his comment below.
Conclusion
I hope this post has helped clarify any confusion caused by the
“d” in ASP.NET 3.5’s JSON serialized ASMX services, and made you
aware of why it’s worth the hassle. As
sophisticated as XSS exploits have become in recent years,
unexpected script execution has the potential for devastating
consequences. That extra “d” is well worth the short-term
hassle.
Microsoft often catches flak over security related issues, but
rarely gets credit when they do things right. I, for one, think the
ASP.NET team deserves credit for remaining vigilant and often
preempting these exploits for us.
Thanks, guys.