title: Calling WCF/JSON/REST WebService from JavaScript using jQuery/Ajax
body: <p>I know there are a lot of questions out there about this - believe me I've read a lot of them and tried the answers out. </p>
  
  <p>(This project is for an internal company lan, not the internet)</p>
  
  <p>We have a WCF webservice which is RESTFUL and sends/receives JSON, it requires NTLM (Kerb would also be good) auth/credentials to ensure that the calling user (from the browser is who they say they are), and this is negotiated between the browser/client and the service by the WCF bindings:</p>
  
  <pre><code> &lt;bindings&gt;
    &lt;webHttpBinding&gt;
      &lt;binding name="webHttpBindingAuth"&gt;
        &lt;security mode="TransportCredentialOnly"&gt;
          &lt;transport clientCredentialType="Ntlm"/&gt;
        &lt;/security&gt;
      &lt;/binding&gt;
    &lt;/webHttpBinding&gt;
  &lt;/bindings&gt;
  </code></pre>
  
  <p>Using Fiddler, I can call the methods on the service GET and POST successfully and provided I adjust the JSON we're sending to the webservice (to include the session ID for example) it trundles along happily.</p>
  
  <p>The problems started when we tried to use JavaScript/jQuery to call the webservice; the idea is that a web server will supply the HTML/JS to the client browser, the browser should then call the WCF webservice to get a session and allow a user to perform a few actions (we have 3 methods in total).</p>
  
  <p>Firstly, we ran into the X-Domain issue, which we tried to resolve by getting the <strong>web server</strong> to return the correct headers (Access-Control-Allow-Origin). This didn't prevent browsers like SRIron from telling us that;</p>
  
  <pre><code>XMLHttpRequest cannot load http://{webServiceUri}/InstantMessagingService/chat/start/{username}. Origin http://{web**Server**Uri} is not allowed by Access-Control-Allow-Origin.
  </code></pre>
  
  <p>Following this, I investigated the possibility of using Silverlight (doesn't seem to support NTLM auth over WebHttpBinding), reverse proxy is out, as the IIS server being used in dev won't be used in prod (I <em>believe</em> it is WebSphere, but not under our control); next I looked at this:</p>
  
  <p><a href="http://msmvps.com/blogs/paulomorgado/archive/2007/04/27/wcf-building-an-http-user-agent-message-inspector.aspx" rel="nofollow noreferrer">http://msmvps.com/blogs/paulomorgado/archive/2007/04/27/wcf-building-an-http-user-agent-message-inspector.aspx</a></p>
  
  <p>Which left me under the impression that the WCF web service was in fact the thing that needed to tell the browser where it was allowed be called from (if that makes sense). Having implemented all the code from the example, I found that the ApplyClientBehavior was never called to attempt to return the headers to the client (monitoring this in Fiddler too). Some more Googling led me to:</p>
  
  <p><a href="http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/707aa031-f4ff-47ab-ba5b-730f7930605e/" rel="nofollow noreferrer">http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/707aa031-f4ff-47ab-ba5b-730f7930605e/</a></p>
  
  <p>Since we're accessing the web service using jQuery and not some .NET client/service reference/proxy/app.. blah, I'm thinking that it's not possible to pre-request-send these headers to allow access to the service. Also, Fiddler seems to think that it's getting a 401 Unauthorized when it does make the attempt to call the <a href="http://../chat/start/" rel="nofollow noreferrer">http://../chat/start/</a>.. method.</p>
  
  <p>Here's the jQuery I'm using to attempt to make the call (I supplied a few settings in the hope it was going to work):</p>
  
  <pre><code>var url = webserviceUrl + "chat/start/" + remoteUserUri;
  
  $.ajax({
      type: 'GET',   
      url: url,
      crossDomain: true,
      beforeSend: function(xhr){ xhr.withCredentials = true; },
      contentType: "application/json; charset=utf-8",               
      success: function (data) { conversationStarted(data); },
      dataType: 'json'
  }); 
  </code></pre>
  
  <p>Ok, if anyone has helpful hints or ideas, please fire away. I'll reply and edit etc. to make sure this is kept up to date, I hope I haven't missed anything (but my heads spinning a little from my Googling).</p>
  
  <p>Also, I know that there might be better ways to do this, but I'd like to do it in the cleanest/quickest way from where I am now - i.e. not a lot of code changes, rewrites etc. I can also post up configs if people think they really are useful.</p>