Saturday, 2 March 2013

How to return Jsonp from WebApi

This allows you to make service requests from jQuery to a different domain (cross site scripting).

1. Add a Formatters folder to your WebApi project and add the following class:

public class JsonpMediaTypeFormatter : JsonMediaTypeFormatter
{
private readonly HttpRequestMessage _request;
private string _callbackQueryParameter;

public JsonpMediaTypeFormatter()
{
SupportedMediaTypes.Add(DefaultMediaType);
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/javascript"));

MediaTypeMappings.Add(new UriPathExtensionMapping("jsonp", "application/json"));
}

public JsonpMediaTypeFormatter(HttpRequestMessage request)
: this()
{
_request = request;
}

public string CallbackQueryParameter
{
get { return _callbackQueryParameter ?? "callback"; }
set { _callbackQueryParameter = value; }
}

public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, HttpRequestMessage request, MediaTypeHeaderValue mediaType)
{
if (type == null)
throw new ArgumentNullException("type");
if (request == null)
throw new ArgumentNullException("request");

return new JsonpMediaTypeFormatter(request) { SerializerSettings = SerializerSettings };
}

public override Task WriteToStreamAsync(Type type, object value, Stream stream, HttpContent content, TransportContext transportContext)
{
string callback;
if (IsJsonpRequest(_request, out callback))
{

var writer = new StreamWriter(stream);
writer.Write(callback + "(");
writer.Flush();

return base.WriteToStreamAsync(type, value, stream, content, transportContext).ContinueWith(_ =>
{

//TODO: Inspecting the task status and acting on that is better
writer.Write(")");
writer.Flush();
});
}

return base.WriteToStreamAsync(type, value, stream, content, transportContext);
}

private bool IsJsonpRequest(HttpRequestMessage request, out string callback)
{
callback = null;

if (request == null || request.Method != HttpMethod.Get)
{
return false;
}

var query = HttpUtility.ParseQueryString(request.RequestUri.Query);
callback = query[CallbackQueryParameter];

return !string.IsNullOrEmpty(callback);
}
}
image

2. Add a FormatterConfig class to your App_Start folder

public class FormatterConfig
{
public static void RegisterFormatters(MediaTypeFormatterCollection formatters)
{
formatters.Remove(formatters.JsonFormatter);
formatters.Insert(0, new JsonpMediaTypeFormatter
{
SerializerSettings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
}
});
}
}
image

3. Update your Global.asax.cs file to register the FormatterConfig

public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
FormatterConfig.RegisterFormatters(GlobalConfiguration.Configuration.Formatters);
}
}

That's it!


How to test your service call


Now your services can be called for Json or Jsonp.


Json


You can continue to get your Json response in the normal way:  http://localhost:2626/api/underlyings


image



image


image


Jsonp


You can now call your service passing in the callback to receive Jsonp:

$.getJSON("http://localhost:2626/api/underlyings/jsonp?callback=?", function (result) {
// process response
});

You’ll see here that the response wraps the data in a jQuery function.


image


image


image


Here’s the HTML code I used in this example:

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Jsonp test</title>
<script src="Scripts/jquery-1.9.1.min.js" type="text/javascript"></script>
</head>
<body>
<button id="getjsonp">Get JSONP</button>
<h4>Request result:</h4>
<div id="jsonp"></div>

<script type="text/javascript">
$(document).ready(function () {
$("#getjsonp").click(function () {
$.getJSON("http://localhost:2626/api/underlyings/jsonp?callback=?", function (result) {
$(result).each(function(index, item) {
$('#jsonp').append('<p>' + item.currencyPair + '</p>');
});
});
});
})
</script>
</body>
</html>





For a working downloadable example I recommend downloading the WebApiContrib solution for Jsonp:


https://github.com/WebApiContrib/WebApiContrib.Formatting.Jsonp

11 comments:

  1. Thank you for a very informative article and example! Just what I needed.

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. formatters.Remove(formatters.JsonFormatter);
    formatters.Insert(0, new JsonpMediaTypeFormatter
    {
    SerializerSettings = new JsonSerializerSettings
    {
    ContractResolver = new CamelCasePropertyNamesContractResolver()
    }
    });

    In this code there is an exception generate......
    System.ArrayTypeMismatchException was unhandled by user code
    HResult=-2146233085
    Message=Attempted to access an element as a type incompatible with the array.
    Source=mscorlib
    StackTrace:
    at System.Collections.Generic.List`1.Insert(Int32 index, T item)
    at System.Collections.ObjectModel.Collection`1.InsertItem(Int32 index, T item)
    at System.Collections.ObjectModel.Collection`1.Insert(Int32 index, T item)
    at CityMax.Mobile.Sample.API.MvcApplication.Application_Start() in d:\CMSPL-Projects\CityMax.Mobile.Sample\ProductiveT.Mobile.Sample.API\Global.asax.cs:line 20
    InnerException:


    Please answer as soon as possible.

    ReplyDelete
  4. I love the blog. Great post. It is very true, people must learn how to learn before they can learn. lol i know it sounds funny but its very true. . .
    python Online training in chennai
    python Online training in bangalore
    python interview question and answers

    ReplyDelete
  5. Thanks for the informative article. This is one of the best resources I have found in quite some time. Nicely written and great info. I really cannot thank you enough for sharing.
    Selenium training in Chennai

    Selenium training in Bangalore

    ReplyDelete
  6. This is an awesome post.Really very informative and creative contents. These concept is a good way to enhance the knowledge.I like it and help me to development very well.Thank you for this brief explanation and very nice information.Well, got a good knowledge.
    Data Science course in rajaji nagar
    Data Science with Python course in chenni
    Data Science course in electronic city
    Data Science course in USA
    Data science course in pune | Data Science Training institute in Pune

    ReplyDelete
  7. Very nice post here and thanks for it .I always like and such a super contents of these post.Excellent and very cool idea and great content of different kinds of the valuable information's.
    rpa training in bangalore
    best rpa training in bangalore
    rpa training in pune | rpa course in bangalore
    rpa training in chennai

    ReplyDelete
  8. Really you have done great job,There are may person searching about that now they will find enough resources by your post
    Best Devops Training in pune
    Devops Training in Bangalore
    Microsoft azure training in Bangalore
    Power bi training in Chennai

    ReplyDelete
  9. After reading this web site I am very satisfied simply because this site is providing comprehensive knowledge for you to audience.
    Thank you to the perform as well as discuss anything incredibly important in my opinion. We loose time waiting for your next article writing in addition to I beg one to get back to pay a visit to our website in




    Selenium training in bangalore
    Selenium training in Chennai
    Selenium training in Bangalore
    Selenium training in Pune
    Selenium Online training

    ReplyDelete