Cross Domain Requests with WCF Data Services and datajs

I have been developing a project that uses WCF Data Services 5.0 and datajs 1.1.0. Everything was working fine until I decided to move the client and service into separate projects. Once they were in separate projects, when I would launch them, they would, as expected, run on different localhost ports and therefore be running on different domains.

It was at this point the client stopped working. I noticed via fiddler that instead of making a GET request to the OData service, the browser based client was instead using the OPTIONS verb and the service was responding with a “501 – Not Implemented”.

I figured that this had something to do with the browser cross-domain policy, but wasn’t quite sure what to do. It was amazing to me that there didn’t appear to be a built-in/simple way to resolve this seemingly common issue. After a bit of googling, I found an MSDN blog post entitled, Getting JSON Out of WCF Data Services, by Glenn Gailey, that mentions a couple ways to get a service to format its response in JSONP (JSON with Padding).

I figured that the option involving the WCF Data Services Toolkit would be the easiest and attempted that first. The toolkit is available via nuget, so it was easy to install. But I ran into problems surrounding assembly conflicts. After struggling a while with that, I gave up and attempted the other option, JSONP and URL-controlled format support for ADO.NET Data Services.

After working with this next solution, I discovered that it didn’t work for WCF Data Services 5.0. I wish I would have taken the time the read the comments on the project’s page, because I had to learn the hard way why it didn’t work. The solution allows you to add the JSONPSupportBehavior attribute to your service class, which then attaches an inspector to the service to check for the $format and $callback query string parameters and then modifies the HTTP headers accordingly. For versions less than 5.0, the accepts header can be “application/json, text/plain;q=0.5” but I eventually learned that version 5.0 requires the header to be “application/json;odata=verbose”. I updated the JSONPSupportBehaviour.cs file accordingly.

WCF Data Service:

[JSONPSupportBehavior]
public class SampleService : DataService<SampleEntities>
{
    public static void InitializeService(DataServiceConfiguration config)
    {
        // ...
    }
}

JSONPSupportBehaviour.cs:

// replace the Accept header so that the Data Services runtime
// assumes the client asked for a JSON representation
httpmsg.Headers["Accept"] = "application/json;odata=verbose";
httpmsg.Headers["Accept-Charset"] = "utf-8";

Once I got all that figured out, I realized that datajs wasn’t including the $callback and $format parameters in the query string. Eventually I came across a post from the datajs project forum which gave some clarification on this whole issue and stated that the enableJsonpCallback needed to be set to true on the OData.read request. After making this final change, my client and service were able to communicated together just fine.

OData.read({
    requestUri: url,
    enableJsonpCallback: true
},
function (data, response) {
    // success
},
function (error) {
    // failure
});

Leave a comment