Using JSONP in ASP.NET MVC

Introduction

For security reasons browsers don't allow cross-domain communication. However,in some legitimate situations cross-domain communication becomes necessary. A common work-around for this restriction is to use JSON with Padding or JSONP. Using JSONP,you return data to a caller embedded in a script. In this article you will learn how JSONP can be used in an ASP.NET MVC application.

Understanding JSONP

Before you actually go into the code level details of using JSONP in ASP.NET MVC,let's see how JSONP works. Consider that you have two domains,website1.com and website2.com. A page from website1.com wants to retrieve some data from a resource belonging to website2.com. If the page and the resource would have been part of the same web site,you could have easily make an Ajax request using $.ajax() or jQuery or XMLHttpRequest object. However,since the page and the resource belong to two different web sites,the browser won't allow such communication due to possible security threats.

Though browsers are reluctant to make cross-domain requests,they happily allow certain HTML tags to point to cross-domain resources. The HTML tags such as <script>,<img> and <iframe> can point to resources outside their current domain using the src attribute. So,you can point a <script> tag to a remote resource that processes and returns some data to your page. However,merely using the <script> tag to point to the remote resource is not of much use because even though the remote resource returns data,the data is merely embedded in the page. You cannot access this returned data for some meaningful purpose.

In JSONP,the remote resource doesn't return plain data to the caller. It returns the data by wrapping it in a JavaScript function call. The JavaScript function name is usually supplied by the caller. The page making the request contains that function. Just to make this concept clear,consider the following example.

Let's say you wish to return data from a remote resource in this form:

 
 
  1. {"CustomerID" : "ALFKI", "Country" : "USA"}

The calling page from website1.com will initiate request to the remote resource like this:

 
 
  1. http://www.website2.com/dataprocessor?callback=MyCallbackFunction

The remote resource (dataprocessor) will process the request and will return the data as follows:

 
 
  1. MyCallbackFunction("{"CustomerID" : "ALFKI","Country" : "USA"}");

The calling page will have MyCallbackFunction() defined somewhere that will be invoked by the browser.

 
 
  1. function MyCallbackFunction(data)
  2. {
  3. //process data further
  4. }

As you can see from the above example,JSONP uses JSON data and pads it with some script to make it a function call.

Creating an ASP.NET MVC Application that Returns Data

Now,that you know what JSONP is and how it works,let's develop an ASP.NET MVC application that returns data to the caller. This application represents the remote resource and consists of a controller named Home. The Home controller contains an action method named GetData(). The GetData() method is shown below:

 
 
  1. [HttpGet]
  2. public JsonpResult GetData(string id)
  3. {
  4. NorthwindEntities db = new NorthwindEntities();
  5. var data = from item in db.Customers
  6. select new { CustomerID=item.CustomerID,Country=item.Country };
  7. JsonpResult result = new JsonpResult(data.SingleOrDefault());
  8. return result;
  9. }

The GetData() method accepts one string parameter - id - that represents a CustomerID. The return type,if GetData() method,is JsonpResult. The JsonpResult is a custom action result class derived from the inbuilt JsonResult class. You will develop the JsonpResult class shortly. Inside,the GetData() method retrieves a Customer from the Customers table of Northwind database. The Customers table contains many columns but the code returns only CustomerID and Country columns. The Customer data is converted into JSONP format using the JsonpResult class and then returned to the caller.

The JsonpResult class used in the above code is shown next.

 
 
  1. public class JsonpResult : JsonResult
  2. {
  3. object data = null;
  4. public JsonpResult()
  5. {
  6. }
  7. public JsonpResult(object data)
  8. {
  9. this.data = data;
  10. }
  11. public override void ExecuteResult(ControllerContext controllerContext)
  12. {
  13. if (controllerContext != null)
  14. {
  15. HttpResponseBase Response = controllerContext.HttpContext.Response;
  16. HttpRequestBase Request = controllerContext.HttpContext.Request;
  17. string callbackfunction = Request["callback"];
  18. if (string.IsNullOrEmpty(callbackfunction))
  19. {
  20. throw new Exception("Callback function name must be provided in the request!");
  21. }
  22. Response.ContentType = "application/x-javascript";
  23. if (data != null)
  24. {
  25. JavaScriptSerializer serializer = new JavaScriptSerializer();
  26. Response.Write(string.Format("{0}({1});", callbackfunction, serializer.Serialize(data)));
  27. }
  28. }
  29. }
  30. }

The JsonpResult class inherits from JsonResult. The JsonResult class is an inbuilt class provided by ASP.NET MVC and represents the data in JSON format. The parameterized constructor of the jsonpResult class accepts an object that represents the data to be wrapped in JSONP form. The ExecuteResult() method is where all the main logic goes. Notice the code marked in bold letters. The code first grabs a query string parameter named callback. This parameter will hold the name of the JavaScript function acting as a callback. Though you can use any name for the query string parameter,the commonly used parameter names are callback and jsoncallback.

The next "if" condition checks if the callback function name is supplied. If it's not then an exception is thrown since callback function is necessary for JSONP to work. The code then sets the ContentType property of the Response object to application/x-javascript because it returns a JSONP string as explained earlier. An instance of the JavaScriptSerializer is then created. The Serialize() method of the JavaScriptSerializer class serializes the supplied data after converting it to JSON format. Notice how the string format is provided while sending the JSON data back. The string.Format() method uses two placeholders and the resultant string will be a function call.

Creating an ASP.NET MVC Application that Consumes the Data

Now,let's create another ASP.NET MVC application that calls the GetData() action method developed earlier. The following code shows the Index view of the second application.

 
 
  1. <script>
  2. function MyCallback(data) {
  3. alert(data.CustomerID + " - " + data.Country);
  4. }
  5. </script>
  6. <script src="http://localhost:1044/home/GetData?id=ALFKI&callback=MyCallback"></script>

The above code contains a <script> block that defines a function named MyCallback(). This function acts as a callback for the JSONP request. The MyCallback() function simply displays the CustomerID and Country of the returned Customer object. Then a <script> tag is used to point to the GetData() action method developed earlier. The src attribute of the <script> tag points to the GetData action and passes two query string parameters viz. id and callback. The id query string parameter is supplied to the GetData() method whereas the callback parameter is used by the JsonpResult class discussed earlier.

If you run the Index view of the client application you will get an alert box as shown below:

Using jQuery for Making JSONP Requests

Though the technique of invoking a JSONP request as illustrated in the preceding section worked as expected,it was a bit raw way of making JSONP requests. Luckily,jQuery offers an inbuilt way to use JSONP in your script. The $.ajax() and $.getJSON() method can be used to make JSONP requests on remote resources. The following code shows how they are used:

 
 
  1. $.ajax({
  2. url: "http://localhost:1044/home/GetData",
  3. data: { id: 'ALFKI' },
  4. type: "GET",
  5. dataType: "jsonp",
  6. jsonp:"callback",
  7. success: function (data) {
  8. alert(data.CustomerID + " - " + data.Country);
  9. }
  10. });
  11. $.getJSON("http://localhost:1044/home/GetData?id=ALFKI&callback=?", function (data) {
  12. alert(data.CustomerID + " - " + data.Country);
  13. });

The first piece of code shown above uses $.ajax() technique whereas the second piece of code uses $.getJSON() technique. While using the $.ajax() method,the dataType is specified as jsonp and the callback query string parameter is specified as callback using the jsonp option. While using the above mentioned jQuery techniques you need not specify a callback function name while making a JSONP request. This is because jQuery automatically creates a random function and sends along with the request. The returned data is processed by the success handler function of the respective calls. So,the code that you put inside MyCallback() function now resides inside the success handler functions of $.ajax() and $.getJSON() methods.

If you run the Index view after adding this markup,you will get the same results as in the previous run.

Summary

Browsers don't let you make cross-domain requests due for security reasons. JSON with Padding or JSONP provides a work-around that allows you to make cross-domain requests and return script rather than data. While making a JSONP request you supply a callback function name in the query string. The remote resource then returns a script equivalent to the function call and passes the data to the function as a parameter. Using JSONP you can achieve cross-domain communication in legitimate scenarios.

相关文章

文章浏览阅读2.4k次。最近要优化cesium里的热力图效果,浏览...
文章浏览阅读1.2w次,点赞3次,收藏19次。在 Python中读取 j...
文章浏览阅读1.4k次。首字母缩略词 API 代表应用程序编程接口...
文章浏览阅读802次,点赞10次,收藏10次。解决一个JSON反序列...
文章浏览阅读882次。Unity Json和Xml的序列化和反序列化_uni...