By Sergio Cavazos.
Quite recently we had to develop an API to expose some data among a MVC3 site, this data would be consumed at 3rd party domains via JSON, thus meaning that due to browser security restrictions, asynchronous requests to cross domains are restricted. Researching a little we found that there’s a technic called JSONP which allows you achieve this.
What is JSONP ?
Known for JSON Padding, in this technic, an “?callback= “ is added to the querystring, so server would process the request, and instead of returning a JSON object or XML, it responds with an “application/x-javascript” response using the callback parameter as a wrapper function, so when request is answered, the browser will execute the JavaScript returned.
Note: Serverside services have to be enabled or tweaked to handle JSONP requests
Applying JSONP in MVC3
First of all let’s see the code that makes the magic:
public class JsonpResult : JsonResult
{
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
var request = context.HttpContext.Request;
var response = context.HttpContext.Response;
string jsoncallback = (context.RouteData.Values["callback"] as string) ?? request["callback"];
if (!string.IsNullOrEmpty(jsoncallback))
{
if (string.IsNullOrEmpty(base.ContentType))
{
base.ContentType = "application/x-javascript";
}
response.Write(string.Format("{0}(", jsoncallback));
}
base.ExecuteResult(context);
if (!string.IsNullOrEmpty(jsoncallback))
{
response.Write(")");
}
}
}
If you notice, our class JsonpResult extends from JsonResult, it overrides the ExecuteResult method in which it seeks for the callback parameter, and if found, it changes response.ContentType and wraps the resulting JSON data using the callback parameter value.
Heres an example of a method of a controller using it
public ActionResult GetJsonFeed(string eventIds)
{
//get rid of any spaces
eventIds = eventIds.Replace(" ", string.Empty);
//cast so we get a long[]
var resp = GetEvents(eventIds.Split(new char[]{','})
.Select(x=>long.Parse(x)).ToArray());
return new JsonpResult{
Data = resp,
JsonRequestBehavior = JsonRequestBehavior.AllowGet
} ;
}
And finally to consume this, we might find Jquery pretty useful
$.ajax({
url: "http://3rdpartydomain.com/EventFeedJson",
type: "get",
data: {
eventIds:"1059849, 1059850, 1059851, 1059852, 1059853, 1059854, 1059855, 1059856, 1059857, 1059858"
},
contentType: "application/json; charset=utf-8",
dataType: "jsonp",
jsonpCallback: "myFunct",
error: function(jqXHR, textStatus, errorThrown){
alert(errorThrown + textStatus + jqXHR);
}
});
function myFunct(data){
alert(data);
}
So if you are in the need to expose data so it can be consumed via asynchronous requests from other domains you can use this. Hope you found this useful.