Asp.net MVC 2 with JSONP and jQuery
Greg Roberts
Greg RobertsI’m willing to bet as a web developer there will be some project that you are working on that requires you to expose your data and or services across domain boundaries through an REST API and want them to be called via javascript. Maybe you wrote a jQuery plugin that retrieves data from your site, or maybe you have several domains that share the same services. Whatever the reason is, you will quickly discover the browser same-origin policy, which states “a web page served from domain1.com cannot normally connect to or communicate with a server other than domain1.com”.
Fortunately there is a way around this. It’s called JSONP or “JSON with padding”. To summarize, JSONP works around the cross-domain browser restriction by making a GET request using a script tag, which isn’t limited by the same-origin policy. It traditionally will also provide a callback method in the url so the response from the server will look something like this:
This call is then executed, and voila you have your data. Now the complexity of how to do this in JavaScript is masked by most JavaScript libraries, like jQuery. I’m going to focus on how you enable this in Asp.net MVC 2.
- The first thing you need is the ability for your controller to return JSON or JSONP base on the request. As far as I know, there is not an out of the box JSONP Action Result in MVC, so we will create one.
The real meat of the class is where we write out the JSON result to the response object with it wrapped in the callback function:
response.Write(jsonp.Item2 + "(" + Data.ToJSON(useDataContract) + ")");
Notice there is also a line there that changes the JSonRequestBehavior settings to AllowGet. If we don’t do this then MVC 2 will barf on the response because of a known security vulnerability with GET requests and JavaScript arrays (more info here).
I’m also using some JSON serialization extension methods that make serializing a bit simpler. Here is the source for ToJSON, it takes a boolean which indicates whether you want the DataContractJsonSerializer or JavaScriptSerializer. Each has it’s own benefits.
Finally all you need to do to use this new action result is pass it your data and other options you care about. By default, it will use JavaScriptSerializer with the jQuery default callback name.
Test: To test that JSONP does in fact work across domains, use jsfiddle.net , my new favorite JavaScript test site, and point it at your local services. In the sample app on codeplex there is a link to the fiddle that I created at the bottom of the master page. Or you can look at it here, http://jsfiddle.net/FSnpp/1/. To do the request in jQuery, just change the Ajax options parameter dataType to ‘jsonp’ or use getJSON and add the callback parameter manually.
Important: The implementation of JSONP in jQuery is not without some flaws, one being it doesn’t raise errors when timeouts or error responses are given. Fortunately there is a plugin that handles that for you. I recommend looking at it if you get serious in consuming JSONP. http://code.google.com/p/jquery-jsonp/
Note: It the action result will default to just returning regular JSON if a callback parameter can’t be found in the request. This means you can use this instead of the JsonResult for even normal requests and they will automatically handle JSONP.
Source: Full Source and Demo is available on Codeplex
info
Codeplex is shutting down, I extracted the archive here.