• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Never worry about ASP.NET AJAX’s .d again

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

Never worry about ASP.NET AJAX’s .d again

AJAX, ASP.NET, JavaScript, jQuery By Dave Ward on June 29th, 2009

When I recently received this message from a frustrated reader:

After hours and hours of slamming my head into the desk it turns out it was the darn "d" in the response. My home computer is on .NET 2.0 and my work computer is on 3.5. Jimminie Christmas!

I realized that the “.d” introduced in ASP.NET AJAX 3.5’s JSON responses is still all too common a stumbling block when calling ASP.NET AJAX services through a library such as jQuery. In fact, with jQuery’s popularity among ASP.NET developers on the rise, this appears to have become an even more frequent problem.

Since a lot of people are having trouble with it, I want to share one method you can use to completely isolate your code from the problem. If you bake this into an $.ajax() code snippet or otherwise use it as a template for calling ASP.NET AJAX services in jQuery, you should never have to think or worry about the “.d” again.

In this post, I will show you how to detect the “.d” and how you can completely isolate your $.ajax success handler from it.

 

“.d” what?

If you aren’t familiar with the “.d” I’m referring to, it is simply a security feature that Microsoft added in ASP.NET 3.5’s version of ASP.NET AJAX. By encapsulating the JSON response within a parent object, the framework helps protect against a particularly nasty XSS vulnerability.

Before ASP.NET 3.5, “ScriptServices” and page methods returned their data at the top level of the JSON response, like this:

In ASP.NET 3.5 and later, the same server-side code returns this:

For more information about the change and why the change is a good one, be sure to see my earlier post: A breaking change between versions of ASP.NET AJAX.

However, what my previous post lacks is a solution for mitigating the inconsistency entirely. Using different client-side code against 2.0 and 3.5 based services is workable, but far from ideal. Wouldn’t it be nicer to not have 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 way to test for its presence. Though JavaScript provides several methods for determining this, I suggest hasOwnProperty, as recommended by Douglas Crockford.

By using hasOwnProperty, your code is protected against unexpected changes to an object’s prototype chain. Though it is an unlikely problem to encounter, it’s always best to code defensively in JavaScript. The browser is a hostile environment!

Using hasOwnProperty to test for “.d”, you might end up with something like this:

$.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 have no .d.
}

This code will perform identically against any version of ASP.NET AJAX.

Unfortunately, this might still get in your way. You may not always want to use the response in a call to another function, and you’ll have to remember the conditional every 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 free to integrate the “.d” handling into a generic $.ajax code snippet in Visual Studio and/or easily copy-paste it between files without modification.

Luckily, jQuery provides a mechanism that allows us to do just that: dataFilter.

The dataFilter parameter to $.ajax allows you 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 value of that callback, and then passes the modified data into your success handler.

Hence, you can forever stop worrying about that pesky “.d” like this:

$.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 has 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 will 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:

// ASP.NET 2.0 with the ASP.NET AJAX Extensions installed.
{'foo':'bar'}
 
// ASP.NET 3.5 and 4.0.
{'d':{'foo':'bar'}}

Your success handler will simply receive this consistent JSON object every time:

{'foo':'bar'}

dataType: none of your business

It’s important to note the removal of the dataType parameter in the $.ajax() code above. This is required in order to prevent a double-eval of service responses containing only 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) is “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 way back to the success callback either way.

However, if the dataType is set to “json” and the “.d” sanitized response happens to be of JavaScript type “string”, jQuery will assume that it is a JSON response from the server and still needs to be deserialized. That will throw an error at best.

The solution is to simply drop the dataType parameter from the $.ajax() call. It is only needed for purposes of instructing jQuery how to deserialize the response, and we’re handling that ourselves now.

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 now (as of jQuery 1.3.2), this is the same mechanism that jQuery uses to deserialize JSON too. Though eval() is potentially evil, it is still a necessary evil in many browsers.

In my next post, I’ll show you how to modify this to leverage a native browser implementation of JSON.parse instead of eval(), available in some newer browsers.

转载自:http://encosia.com/never-worry-about-asp-net-ajaxs-d-again/


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
Asp.Net自定义错误页面发布时间:2022-07-10
下一篇:
Asp.net MVC]Asp.net MVC5系列——实现编辑、删除与明细信息视图发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap