JSONP AJAX and ASP.NET Demystified

JSONP is essentially a new name for an old trick. AJAX calls are done using the XMLHttpRequest object which is supported in all major browsers. But, there is a cross-domain limitation placed on XMLHttpRequest calls. This means that you can only communicate from the browser back to the domain from which the JavaScript was served.

This is where JSONP comes in. JSONP stands for JSON with Padding. While XMLHttpRequest traffic is restricted to the server of origin, there is no such restriction on from where you can load JavaScript source by using the standard <script> tag.  Most developers know that you can load jQuery libraries from a CDN by pointing your <script> "src" attribute to the CDN URL for the given JavaScript library. It doesn't matter where the domain is - the script will load just fine. This "security hole", if you will -- has been used for years by major players including Google for Adsense, Yahoo and many others, and is therefore not likely to be changed anytime soon. In fact, it was used when AJAX was originally called "Remote Scripting" - which is as early as 1998, when it was used by Microsoft in Outlook Web Access.

How it works

What JSONP does is that instead of using XMLHttpRequest, it will dynamically create a <script> tag to get the data.  A <script> tag does not have to return JavaScript -- it will load whatever is returned from the URL specified as its “src” attribute.    

Instead of specifying the <script> src attribute as:

JSONP appends a parameter named callback to the URL, so we have this as the src attribute:

JSONP requests are not dispatched using the XMLHTTPRequest at all; instead a <script> tag is created whose source is set to the target URL. This script tag is then added to the DOM -- normally the <head>. The advantage of doing this with the jQuery library is that everything is standardized and you don't have to worry about "plumbing" at all.

A web service or API that supports the JSONP protocol will see this callback attribute on the request url and instead of just returning the JSON data as before, it will wrap the data with a method call of the same name specified by this callback parameter.  So the data the web service returns will now look like this:

mycallback({[..JSON  data here..]})

After the data loads, we end up with a <script> tag in the page that looks like this:

mycallback({[..JSON  data here..]})    

Since this is done dynamically in the receiving page, the new script executes, immediately making the call to the callback method, supplying the JSON data, which "materializes" the JSON object because it is legal javascript. This is similar to the callbacks that you are able to provide to a traditional Ajax XMLHttpRequest method.

With jQuery, which is widely used by developers now, the JSONP method call takes this form:

dataType: 'jsonp',  
data: 'id=100',  
jsonp: 'jsonpcallback',  
url: 'http://www.server.com/methodname',
success: functionName,
error:   otherfunctionName

The advantage of giving it a name - JSONP -  and specifying exactly how it is to be used is for the sake of conformity and standards. If you ask some vendor if their API supports JSONP and they say "yes", you can be pretty confident that it is a standard implementation.

jQuery also supports a $getJSON function:

  $.getJSON(url + "&jsoncallback=?", function(data){
    Name = data.Name;
    Message = data.Message;

    if(Name != "" && Message != "")
     jQuery("#divMsg").html("Hello " + Name + ", you typed: " + Message);
     jQuery("divMsg").html("Please enter Name and Message to get the result!!!");

Note that with the $getJSON function, the callback is specified on the URL as "&jsoncallback=?".   jQuery is smart enough to  construct a dynamic callback function with a unique name, and this is sent to the server.

In either case, this must be an HTTP GET verb call.  JSONP does not work with POST at all.

Let's use a working example to see how this all fits together. You can copy all the code after this sentence, put it into Notepad, and save it in c:\inetpub\wwwroot\ as JqueryJson.html, and request it with your browser at http://localhost/JqueryJson.html and it should work "out of the box":

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  <TITLE>Flickr API With JSONP</TITLE>   
  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"> </script>    
  <script type="text/javascript">  

var jsonFeed = "http://api.flickr.com/services/feeds/photos_public.gne";  

url: jsonFeed,        
data: { "lang" : "en-us", "format" : "json", "tags" : "sunset" },
dataType: "jsonp",        
jsonp: "jsoncallback",        
timeout: 5000,        
success: function(data, status){
$.each(data.items, function(i,item)

$("<img>").attr("src", (item.media.m).replace("_m.","_s.")).attr("alt", item.title).appendTo("ul#flickr").wrap("<li><a href=\"" + item.link + "\"></a></li>");
if (i == 10) return false;  // don't go crazy
error: function(XHR, textStatus, errorThrown){alert("ERROR: " + textStatus);        

<ul id=flickr>

Call: http://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=jsonp1292276431678&lang=en-us&format=json&tags=sunset
"title": "Recent Uploads tagged sunset",
"link": "http://www.flickr.com/photos/tags/sunset/",
"description": "",
"modified": "2010-12-13T21:20:20Z",
"generator": "http://www.flickr.com/",
"items": [
"title": "",
"link": "http://www.flickr.com/photos/alycassata/5258391795/",
"media": {"m":"http://farm6.static.flickr.com/5046/5258391795_efb400116f_m.jpg"},
"date_taken": "2010-12-11T13:30:19-08:00",
"description": " <p><a href=\"http://www.flickr.com/people/alycassata/\">alycassata<\/a> posted a photo:<\/p> <p><a href=\"http://www.flickr.com/photos/alycassata/5258391795/\" title=\"\"><img src=\"http://farm6.static.flickr.com/5046/5258391795_efb400116f_m.jpg\" width=\"160\" height=\"240\" alt=\"\" /><\/a><\/p> <p>+2 without editing in comments!<\/p>",
"published": "2010-12-13T21:20:20Z",
"author": "nobody@flickr.com (alycassata)",
"author_id": "36599621@N03",
"tags": "park new york city sunset white ny black brooklyn canon eos rebel 50mm model photoshoot f14 desaturated dalton aly fischer cassata 550d t2i alycassata"
"title": "LA Sunset",
"link": "http://www.flickr.com/photos/bdu/5258380431/",
"media": {"m":"http://farm6.static.flickr.com/5003/5258380431_149e0198c0_m.jpg"},
"date_taken": "2010-12-11T17:56:39-08:00",
"description": " <p><a href=\"http://www.flickr.com/people/bdu/\">bdu<\/a> posted a photo:<\/p> <p><a href=\"http://www.flickr.com/photos/bdu/5258380431/\" title=\"LA Sunset\"><img src=\"http://farm6.static.flickr.com/5003/5258380431_149e0198c0_m.jpg\" width=\"240\" height=\"161\" alt=\"LA Sunset\" /><\/a><\/p> ",
"published": "2010-12-13T21:16:19Z",
"author": "nobody@flickr.com (bdu)",
"author_id": "54581307@N00",
"tags": "sunset losangeles griffithobservatory"

I have also provided a standard ASP.NET Visual Studio 2010 Solution that you can download with the page included. Bear in mind that everything in the ASPX Default page is client-side, but it illustrates how easily one can integrate jQuery, AJAX and JSONP into a standard ASP.NET application.

By Peter Bromberg   Popularity  (3746 Views)