• Ajax, Cross Domain, jQuery, WCF Web API or MVC, Windows Azure

    Published by on July 2nd, 2011 10:35 am under Azure, Cross Domain, jQuery, WCF Web API

    5 Comments

    The title is SEO friendly as you can see Smile. This week, while working in a cool project, we had to explore options to expose a web API and make cross domain calls from an HTML5 client. Our specific scenario is: we develop the server API and another company is building the HTML5 client. Since we are in the development phase, we wanted to be agile and work independently from each other.  The fact that we are using Azure and WCF Web API is an implementation detail, this can be applied to any server side REST framework and any platform.

    image

    We wanted a non-intrusive solution. This means being able to use the usual jQuery client (not learning a new client js API) and try to keep to the minimum the amount of changes in the client and server code. JSONP is an option but it does not work for POST requests. CORS is another option that I would like to try but I haven’t found a good jQuery plugin for that.

    So in the end this is what we decided to use:

    • WCF Web API to implement the REST backend (works also with MVC)
    • jQuery to query the REST backend
    • jQuery plugin (flXHR from flensed) that overrides the jQuery AJAX transport with a headless flash component
    • Windows Azure w/ WebDeploy enabled to host the API

    Having a working solution requires the following steps:

    1. Download jQuery flXHR plugin and add it to your scripts folder
    2. Download the latest flXHR library
    3. Put the cross domain policy xml file in the root of your server (change the allowed domains if you want)

      <?xml version="1.0"?>
      <!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
      <cross-domain-policy>
      
        <allow-access-from domain="*" />
        <allow-http-request-headers-from domain="*" headers="*" />
      
      </cross-domain-policy>
      

    Here is some JavaScript code that register the flXHR as a jQuery ajax transport and make an AJAX call when a button is click

    <script type="text/javascript">
        var baseUrl = "http://api.cloudapp.net/";
    
        $(function () {
            jQuery.flXHRproxy.registerOptions(baseUrl, { xmlResponseText: false, loadPolicyURL: baseUrl + "crossdomain.xml" });
        });
    
        $.ajaxSetup({ error: handleError });
    
        $("#btn").click(function () {
            $.ajax({
                url: baseUrl + "resources/1",
                success: function (data) {
                    alert(data);
                }
            });
        });
    
        function handleError(jqXHR, errtype, errObj) {
            var XHRobj = jqXHR.__flXHR__;
            alert("Error: " + errObj.number
            + "\nType: " + errObj.name
            + "\nDescription: " + errObj.description
            + "\nSource Object Id: " + XHRobj.instanceId
        );
        }
    </script>
    

    It’s important to set the ajaxSetup, otherwise POST requests will be converted to GET requests (seems like a bug in the library)

    Finally, make sure to include the following scripts

    <script src="/Scripts/jquery-1.6.2.js" type="text/javascript"></script>
    <script type="text/javascript" src="/Scripts/flensed/flXHR.js"></script>
    <script src="/Scripts/jquery.flXHRproxy.js" type="text/javascript"></script>
    

    The nice thing of this solution is that you can set the baseUrl to an empty string and remove the “registerOptions” and everything will keep working just fine from the same domain using the usual jQuery client.

    This is the client with (default.html)

    image

    This is the server implemented with WCF Web API running in Azure

    image

    Turning on the network monitoring on IE9, we can see what is going on behind the scenes.

    image

    Notice the last two calls initiated by Flash. The first one downloading the crossdomain policy file and then the actual call to the API.

    Some gotchas:

    • I wasn’t able to send http headers (via beforeSend). This means that you can’t set the Accept header, it will always be */*
    • There is no support for other verbs than GET/POST (this is a Flash limitation)

    I uploaded the small proof of concept here.

    Enjoy!

Tags