Note:this Post is part of a long-running series of posts covering the Union of JQuery and ASP.NET:jQuery for the ASP. Developer.
Topics in this series range all the the-the-from-using jquery to enhance Updatepanels-using jquery up to completely manage Rendering and interaction in the browser with ASP. NET only acting as a backend API. If The post you ' re viewing are something that interests you, being sure to check out the rest of the posts in this series.
When I recently received the message from a frustrated reader:
After hours and hours of slamming my head to the desk it turns out it is the darn "D" in the response. My home computer is in. NET 2.0 and my work computer are on 3.5. Jimminie Christmas!
I realized the ". D" introduced in ASP. AJAX 3.5 ' s JSON responses is still all too common a stumbling block when CA lling ASP. NET AJAX services through a library such as JQuery. In fact, with JQuery ' s popularity among ASP. Developers on the rise, this appears to has become an even more frequ Ent problem.
Since A lot of people is have trouble with it, I want to share one method can use to completely isolate your code F Rom the problem. If you bake this to an $.ajax () code snippet or otherwise use it as a template for calling ASP. Ajax Services in Jque Ry, you should never has to think or worry about the ". D" again.
In this post, I'll show you what to detect the '. d ' and how can completely isolate your $.ajax success H Andler from it.
". D" What?
If you aren ' t familiar with the '. d ' I ' m referring to, it's simply a security feature that Microsoft added in ASP. 3.5 ' s version of ASP. By encapsulating the JSON response within a parent object, the framework helps protect against a particularly nasty XSS vu Lnerability.
Before ASP. 3.5, "scriptservices" and page methods returned their data at the top level of the JSON response :
In ASP. 3.5 and later, the same server-side code returns this:
For more information about the "Change " and "Why" is a good one, being sure to see my earlier post:a Breakin G change between versions of ASP.
However, what my previous post lacks are a solution for mitigating the inconsistency entirely. Using different Client-side code against 2.0 and 3.5 based services are workable, but far from ideal. wouldn ' t it is nicer to worry about it?
Determining whether or not the '. d ' Is there
In order to isolate ourselves from the ". D", we first need a reliable-to-test for its presence. Though JavaScript provides several methods for determining this, I suggest hasOwnProperty, as recommended by Douglas Crock Ford.
By using hasOwnProperty, your code was protected against unexpected changes to an object ' s prototype chain. Though It is a unlikely problem to encounter, it's always the best to code defensively in JavaScript. The browser is a hostile environment!
Using hasOwnProperty to test for ". D", you might end up with the something like this:
<textarea class="crayon-plain print-no" style="z-index: 0; opacity: 0; overflow: hidden" readonly="" data-settings="dblclick">$.ajax ({type: "POST", url: "Webservice.asmx/methodname", Data: "{}", ContentType: "Application/json; Charset=utf-8 ", DataType:" JSON ", Success:function (msg) {if (Msg.hasownproperty (" D "))//Leave the. D behind an D Pass the rest of//the JSON object forward. DoSomething (MSG.D); else//No. D; No transformation necessary. DoSomething (msg); }}); function DoSomething (msg) {//do something with the response data here. Expect it to consistently has no. D.}</textarea>
$. Ajax({ type: "POST", URL: "Webservice.asmx/methodname", data: "{}", contentType: "Application/json; Charset=utf-8 ", dataType:"JSON", Success: function(msg) { if (msg. hasOwnProperty("D")) //Leave the. D behind and pass the rest of //The JSON object forward. dosomething(msg. D); Else //No. D; no transformation necessary. dosomething(msg); }});function dosomething(msg) { //Do something with the response data here. //Expect it to consistently has no. d. } |
This code would perform identically against any version of the ASP.
Unfortunately, this might still get in your. Want to use the response in a call to another function, and you'll have to remember the conditional eve Ry time you write a success handler.
Don ' t make me think
I prefer a solution that doesn ' t touch the success handler at all. Then, you're ' re free to integrate the '. d ' handling into a generic $.ajax code snippet in Visual Studio and/or easily copy-pa Ste it between files without modification.
Luckily, JQuery provides a mechanism that allows us to doing just that: datafilter.
The Datafilter parameter to $.ajax allows I to arbitrarily transform a response just before the success handler Fires. Specifically tailored to this sort of situation, it passes response data into a callback function, captures the return Val UE of that callback, and then passes the modified data into your success handler.
Hence, you can forever stop worrying on that pesky ". D" as this:
<textarea class="crayon-plain print-no" style="z-index: 0; opacity: 0; overflow: hidden" readonly="" data-settings="dblclick">$.ajax ({type: "POST", url: "Webservice.asmx/methodname", Data: "{}", ContentType: "Application/json; Charset=utf-8 ", datafilter:function (data) {//This boils the response string down//into a proper JavaScript O Bject (). var msg = eval (' (' + data + ') '); If The response have a ". D" top-level property,//Return to what's below that instead. if (Msg.hasownproperty (' d ')) return MSG.D; else return msg; }, Success:function (msg) {//This would now output the same thing//across any current version of. NET. Console.log (Msg.foo); }});</textarea>
$. Ajax({ type: "POST", URL: "Webservice.asmx/methodname", data: "{}", contentType: "Application/json; Charset=utf-8 ", datafilter: function(data) { //This boils the response string down //into a proper JavaScript Object (). var msg = eval('(' + data + ') ') ; //If The response have a ". D" top-level property, //Return what ' s below that instead. if (msg. hasOwnProperty(' d ')) return msg. D; Else return msg; }, Success: function(msg) { // This would now output the same thing //across any current version of. NET. console. Log(msg. Foo); }}); |
Now, regardless which of these JSON forms the server returns:
<textarea class="crayon-plain print-no" style="z-index: 0; opacity: 0; overflow: hidden" readonly="" data-settings="dblclick">//ASP. 2.0 with the ASP. NET AJAX Extensions installed. {' foo ': ' Bar '}//ASP. 3.5 and 4.0. {' d ': {' foo ': ' Bar '}}</textarea>
//ASP. 2.0 with the ASP. NET AJAX Extensions installed. {' foo ':' Bar '} //ASP. 3.5 and 4.0. {'d ':{' foo ':' Bar '}} |
Your success Handler would simply receive this consistent JSON object every time:
<textarea class="crayon-plain print-no" style="z-index: 0; opacity: 0; overflow: hidden" readonly="" data-settings="dblclick">{' foo ': ' Bar '}</textarea>
Datatype:none of your business
It ' s important to note the removal of the DataType parameter in the $.ajax () code above. This was required in the order to prevent a double-eval of service responses containing with a single string.
Internally, JQuery uses a combination of the DataType parameter and the implicit type the response. If the DataType is "JSON" and typeof (response) are "string" then JQuery uses eval () to deserialize the response.
In the example above, manually deserializing the response in Datafilter results in it being of type Object, JQuery leaves It alone, and our Datafilter ' D object makes its-to-the-success callback either.
However, if the DataType is set to "JSON" and the ". D" sanitized response happens to be of JavaScript type "string", Jquer Y'll assume that it's a JSON response from the server and still needs to be deserialized. That would throw a error at the best.
The solution is to simply drop the DataType parameter from the $.ajax (). It's only needed for purposes of instructing jQuery what to deserialize the response, and we ' re handling that ourselves no W.
Thanks to Brett for pointing this out.
Wait, isn ' t eval () supposed to be evil?
If the eval () usage gives you pause, don ' t worry. For today (as of jquery 1.3.2), this is the same mechanism that jquery uses to deserialize JSON too. Though eval () is potentially evil, it's still a necessary evil in many browsers.
In my next post, I'll show you what to modify leverage a native browser implementation of Json.parse instead of Eva L (), available in some newer browsers.
That's post is available now:improving JQuery ' s JSON performance and security.
Never worry about ASP. NET AJAX ' s. D again