Problem sending JSON data from JQuery to WCF REST method

theburningmonk picture theburningmonk · Feb 2, 2011 · Viewed 26.8k times · Source

I'm having some trouble getting jquery to post some json data to a rest method I have on my WCF service.

On the WCF side, here's the operation contract:

[OperationContract]
[WebInvoke(Method = "POST",
           BodyStyle = WebMessageBodyStyle.Bare,
           RequestFormat = WebMessageFormat.Json,
           ResponseFormat = WebMessageFormat.Json,
           UriTemplate = "PostSomething")]
MyResult PostSomething(MyRequest request);

both MyResult and MyRequest are marked with all the necessary DataContract and DataMember attributes and service is exposing WebHttp endpoint.

On the JQuery side, here's my function call:

var jsonStr = JSON.stringify(reqObj);

$.ajax({
    type: "POST",
    dataType: "json",
    url: "http://localhost/MyService/PostSomething",
    contentType: "application/json; charset=utf-8",
    data: jsonStr,
    success: function (html) {
        alert(html);
    }
});

this request never reaches my method (I get a 405 Method Not Allowed everytime), and looking in Charles the request looks like this:

OPTIONS /MyService/PostSomething HTTP/1.1
Host: localhost
Cache-Control: max-age=0
Access-Control-Request-Method: POST
Origin: null
Access-Control-Request-Headers: Content-Type, Accept
Accept: */*
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

couple of things which is strange about this:

  1. the method is OPTIONS not POST
  2. the content-type (in another tab) shows text/html; charset=UTF-8 instead of json
  3. the JSON data is no where to be seen

However, if I modify the request in Charles so that its headers is similar to the solution here, then everything works:

POST /MyService/PostSomething HTTP/1.1
Content-Type: application/json; charset=utf-8
Host: localhost
Content-Length: 152

{"Id":"", "Name":"testspot","Description":"test" } 

looking at tutorials and other questions on here others have managed to get JQuery to post to a WCF REST method like this, and I'm at a loss as to what I'm doing wrong here..

oh, to put some context, this is a WCF 4 service and I'm using JQuery 1.4.4.

Thanks,

UPDATE:

After some more reading and thanks to Darrel for pointing me towards the cross-domain spec, I managed to get a bit further by making some small changes to my service, on the service interface:

[OperationContract]
[WebInvoke(Method = "*",
           BodyStyle = WebMessageBodyStyle.Bare,
           RequestFormat = WebMessageFormat.Json,
           ResponseFormat = WebMessageFormat.Json,
           UriTemplate = "PostSomething")]
MyResult PostSomething(MyRequest request);

and in the implementation, I need to check if the incoming requests is for OPTIONS and in that case return some headers rather than doing the intended work:

if (WebOperationContext.Current.IncomingRequest.Method == "OPTIONS")
{
    WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
    WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Methods", "POST");
    WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept");

    return null;
}

the method then gets called twice, the first time the server returns null but adds some headers to the client, and then the actual request is made with POST as method and the server goes ahead and deals with the request normally.

Answer

Darrel Miller picture Darrel Miller · Feb 2, 2011

This seems to be a Firefox thing for avoiding cross domain calls. See http://www.petefreitag.com/item/703.cfm

The spec for this is here http://www.w3.org/TR/cors/ and after a very brief read, it appears that because you are doing a cross domain call, your service is expected to implement the OPTIONS method and return some headers that allow the POST method to be sent.