Using jQuery & JSONP for cross-domain AJAX with WCF services
I’m working on a Virtual Earth application that uses AJAX to retrieve points of interest and plot them on the map. The long term direction for this application is to move the data source into the cloud, while the front-end web page is hosted onto a customer site.
For the front-end, I’ve been using jQuery, which now supports cross-domain AJAX with JSON with Padding (JSONP). The back-end is a Windows server with SQL Server 2008.
It’s a bit complicated to get JSONP working with a simple WCF service. Luckily, there’s some sample code on MSDN to do it for you; it’s just not obvious how to take advantage of it. Here it is in 3 “easy” steps!
- Implement and test the WCF service with JSON
- Convert the WCF Service to support JSONP
- Implement the front end with jQuery
1. Implement and test the WCF service with JSON
Get that WCF service up and running, returning plain-vanilla JSON. This takes a whole host of variables out of the mix – the database connection, WCF endpoint configuration (ugh), etc. You want to end up with a working WCF service with an interface somewhat like this:
public interface ILocationService
{
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
Location GetLocation();
}
Test your service with cURL, Fiddler, or another suitable tool. Before you start with JSONP, you want to be able to call this service on localhost with HTTP GET.
My GetLocation web service returns a current location in JSON, like this:
{“Latitude”: 47.621389,”Longitude”:-122.356660}
2. Convert the WCF Service to support JSONP
The MSDN article JSON with Padding (AJAX) has a link to some sample code that will makes JSONP easy. You have to download the massive sample package (just do it, it’s worth it). Once you have the samples unzipped, find the JSONP project in WCFWFCardSpace\WCF\Extensibility\Ajax\JSONP\CS and grab these four files from the service directory:
- JSONPBehavior.cs
- JSONPBindingElement.cs
- JSONPBindingExtension.cs
- JSONPEncoderFactory.cs
Add these files to your project. In a future post I’ll dive into how JSONP works and how these files implement it in WCF. For now, let’s just hook your WCF service up to the JSONP interface.
The Interface
The only thing do to in the code is to add the JSONPBehavior attribute to your interface. The example function GetLocation() above becomes the following:
public interface ILocationService
{
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
[JSONPBehavior(callback = "method")]
Location GetLocation();
}
The (callback = “method”) parameter dictates what query string parameter should be sent in the request URI. We’ll see more about that below.
Configuration
This is where it gets a little hairy. Getting the configuration right is always the most annoying part of implementing a WCF service. Here’s the system.serviceModel section from my Web.config:
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="LocationServiceBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="LocationServiceJSONP.LocationService">
<endpoint address=""
binding="customBinding"
bindingConfiguration="jsonpBinding"
behaviorConfiguration="LocationServiceBehavior"
contract="LocationServiceJSONP.ILocationService">
</endpoint>
</service>
</services>
<bindings>
<customBinding>
<binding name="jsonpBinding" >
<jsonpMessageEncoding />
<httpTransport manualAddressing="true"/>
</binding>
</customBinding>
</bindings>
<extensions>
<bindingElementExtensions>
<add name="jsonpMessageEncoding"
type="Microsoft.Ajax.Samples.JsonpBindingExtension, LocationServiceJSONP,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</bindingElementExtensions>
</extensions>
</system.serviceModel>
Remember the (callback = “method”) parameter in the JSONPBehavior attribute? That’s the key to making sure this works. To trigger the JSONP behavior, you must put a “method” parameter in the query string with the name of the callback method that will be used to wrap the JSON:
http://yourserver.com/LocationService.svc/GetLocation?method=jsonpCallback
This causes the JSON returned by the service to be wrapped in the callback method you specified:
jsonpCallback( {“Latitude”: 47.621389,”Longitude”:-122.356660} );
3. Implement the front end with jQuery
Finally! It’s time to implement this on the front end. In your web page, make the web service call like this:
$.getJSON(“http://yourserver.com/LocationService.svc/GetLocation?method=?”, callback);
function callback(data) {
// data is the JSON returned – do whatever you want with it!
}
The method=? syntax tells jQuery to fill in the “method” parameter with the JSONP callback it generates. The rest is transparent to you – your function gets the unwrapped JSON.
There you go! JSONP lets you do cross-domain web service calls from any web page, as long as the target service supports JSONP.