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
});
Advertisements

C# with Mono

I’ve been wanting to learn C#. It seems everything is done in C# these days. But I have a Mac. I thought that the only way to program with C# would be on Windows XP via WMWare, but after a bit of research I found I was mistaken.

Enter Mono. (Mono, as in the prefix meaning “one,” not as in the disease.) Mono is an open source, cross platform implementation of the .Net Framework. It is available on a large number of platforms, including Mac OS X, Windows and Linux. Sounds cool, eh? That’s what I thought anyway. So I was excited to download and try it. It even comes with it’s own little IDE, MonoDevelop.

After I installed Mono and MonoDevelop, I was able to compile a quick “Hello World” console application. That was fun and easy. I wondered if I would be able to do the same with a Windows.Forms application. This is where I ran into some complications.

Whenever I tried to use System.Windows.Forms, I would get the following error:

The type or namespace name ‘Windows’ does not exist in the namespace ‘System’. Are you missing an assembly reference?

I searched all around to see what this could possibly mean. The Mono Project website said they supported Windows.Forms on Mac OS X. I had the full version of Mono. I reinstalled Mono and MonoDevelop several times. Unfortunately, since Mono is so new and there isn’t much of a Mac community for it, I was lost.

Finally, I stumbled on the Edit References window in MonoDevelop and found what I was missing. To find it:

  1. In the Project menu, select Edit References.
  2. On the Packages tab, scroll down to and select the assembly you wish to include (mine was System.Windows.Forms).
  3. Click OK.

And that’s all there is to it. My “Hello Form” project compiled just fine. It is important to note, that in order for the Edit References option to be available in the Project menu, you need to be working in an active project, or solution. When I was first trying to compile my “Hello Form” program, I had opened it as a single file and that was a mistake.

It might be best to note here also that System is another available assembly in the list. If you ever get a “missing assembly reference” error, check that list!

The code for my “Hello Form” program was very simple:

using System;
using System.Windows.Forms;

namespace HelloForm
{
    public class HelloForm : Form
    {
        public static void Main()
        {
            Application.Run(new HelloForm());
        }
    }
}