Handling JSONP Requests in ASP.NET MVC 3

JSON with Padding (JSONP) is a well-accepted hack to allow for cross origin ajax requests. Instead of making requests the regular XHR / ajax way, JSONP returns results by dynamically writing a script tag into the DOM with the src attribute set to the appropriate URL. Because browsers don't limit the origin of scripts loaded via the script tag, this means that data, via JavaScript, can be loaded from any of literally hundreds of API’s and endpoints that support JSONP.

If you are writing some sort of service or application that needs to be able to return data to clients that originate from a different domain, then JSONP is your friend.

Here is an example jQuery function that makes a request to a server on another domain expecting a jsonp response back, and using Knockout.js to handle data binding:

$(function () {
        $.ajax({
            dataType: 'jsonp',
            url: 'http;//otherdomain.com/Home/GetEmployees', //Normally this would be a url to an application on a different domain for JSONP
            success: function (data) {               
                var viewModel = {
                    FirstName: ko.observable(data[0].FirstName),
                    LastName: ko.observable(data[0].LastName),
                    Address: ko.observable( data[0].Address),
                    City: ko.observable (data[0].City),
                    Region: ko.observable(data[0].Region)
                };
                ko.applyBindings(viewModel);
              
            }
        });
    });

  jQuery is already set up to handle JSONP requests and results easily, and has supported JSONP since version 1.2.

  One of the easiest ways to handle the return of JSONP - style data in your MVC applications is to create a "JsonpResult" ActionResult class:

using System;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Script.Serialization;

namespace JSONPExample.ActionResults
{
    public class JsonpResult : ActionResult
    {
         public string CallbackFunction { get; set; }
         public Encoding ContentEncoding { get; set; }
         public string ContentType { get; set; }
         public object Data { get; set; }
        public JsonpResult(object data) : this(data, null) { }
        public JsonpResult(object data, string callbackFunction)
        {
            Data = data;
            CallbackFunction = callbackFunction;
        }

        public override void ExecuteResult(ControllerContext context)
         {
             if (context == null) throw new ArgumentNullException("context");
            HttpResponseBase response = context.HttpContext.Response;
            response.ContentType = string.IsNullOrEmpty(ContentType) ? "application/x-javascript" : ContentType;

             if (ContentEncoding != null) response.ContentEncoding = ContentEncoding;
             if (Data != null)
            {
                HttpRequestBase request = context.HttpContext.Request;
                var callback = CallbackFunction ?? request.Params["callback"] ?? "callback";
                var serializer = new JavaScriptSerializer();
                 response.Write(string.Format("{0}({1});", callback, serializer.Serialize(Data)));
             }
         }
    }
}

In your Action Method in the controller, you simply go get your data in whatever way your app does this, and then return the data as a JsonpResult rather than as a JsonResult:

public ActionResult GetEmployees()
        {
            var data =  GetDataSomehow();
             //constructor overload for overriding callback function:
            //return new JsonpResult(data, "callback function");
           return new JsonpResult(data);
        }

        private List<Employee> GetDataSomehow()
         {
             // Surrogate for getting some data from your database or other store
           List<Employee> emps = new List<Employee>();
            Employee emp = new Employee()
                               {
                                   Address = "123 High st.",
                                   BirthDate = DateTime.Parse("2/2/1980"),
                                   FirstName = "Joe",
                                   LastName = "Blow",
                                   City = "Yuma",
                                   Region ="AZ",
                                   Country = "US",
                                   EmployeeID = 1,
                                   HomePhone = "999-999-9999"
                               };
            emps.Add(emp);
            return emps;
        }

What the ExecuteResult method does is to simply wrap your serialized JSON data in a javascript function with the name of the requested callback. This returned script block is then injected direcly into the DOM of the client page, and since the JSON it contains is legal javascript, it is executed by the browser. jQuery handles all the dirty work transparently behind the scenes so that as far as you the developer are concerned, it behaves exactly like any other jQuery $.ajax call.

You can download the complete Visual Studio 2010 ASP.NET MVC 3 solution, which also has an example of using Knockout.js for databinding.

By Peter Bromberg   Popularity  (11070 Views)