none
WCF using REST/JSON

    Question

  • Hi,

    I have been putting together a some WCF REST services.  Going off the generic Calculator example, Is there any way to do the following?

     

     [OperationContract]
     [WebInvoke(Method = "POST",
     BodyStyle = WebMessageBodyStyle.Bare,
     RequestFormat = WebMessageFormat.Json,
     ResponseFormat = WebMessageFormat.Json)]
     public double Add(double n1, double n2)
     {
     return Convert.ToDouble(n1 + n2);
     }
    

     

    Without getting this:

     

    Operation 'Add' of contract 'Calculator' specifies multiple request body parameters to be serialized without any wrapper elements. At most one body parameter can be serialized without wrapper elements.

    I really don't want the MS AJAX wrapping around my JSON response objects.  Do I HAVE to use WebGet() in order to use more than 1 parameter with a POST operation?

    Ultimately I'm trying to get this wired up into jQuery (which I'm guessing I'll have to change to GET as well):

     

     $("#btnAddJQ").click(function () {
    
     numLeft = $('#txtNumLeft').val();
     numRight = $('#txtNumRight').val();
     ajaxData = "{'n1':'" + numLeft + "','n2':'" + numRight + "'}"
    
     $.ajax({
     type: "POST",
     url: "http://localhost:9000/Calculator/Add",
     data: ajaxData,
     contentType: "application/json; charset=utf-8",
     dataType: "json",
     success: function (msg) {
     $('#txtAnswer').html(msg.d);
     },
     error: function (request, status, error) {
     alert(status + ' : ' + error);
     //alert(request.responseText);
     }
     });
     });
    

     

    If I end up having to use a GET, would that change my url to something like this?

    http://localhost:9000/Calculator/Add?n1=1.0&n2=2.0

    with the following jQuery?

     numLeft = $('#txtNumLeft').val();
     numRight = $('#txtNumRight').val();
     myUrl = "http://localhost:9000/Calculator/Add?n1=" + numLeft + "&n2=" + numRight
    
     $.ajax({
     type: "GET",
     url: myUrl,
     data: ajaxData,
     contentType: "application/json; charset=utf-8",
     dataType: "json",
     success: function (msg) {
     $('#txtAnswer').html(msg.d);
     },
     error: function (request, status, error) {
     alert(status + ' : ' + error);
     }
     });
    


    I also heard there was a way to use JSON in the query string. Something like this:

    http://example.com/myservice.svc/MyOperation?number=7&p={"name":"John","age":42}

    Does it only work where the input parameters are complex data types like a Person (in above)?

     

    Also out of curiosity, I tried doing POST WebMessageBodyStyle.Wrapped combination but I was not too sure how the json request was supposed to be formatted.

     [OperationContract]
     [WebInvoke(Method = "POST",
     BodyStyle = WebMessageBodyStyle.Wrapped,
     RequestFormat = WebMessageFormat.Json,
     ResponseFormat = WebMessageFormat.Json)]
     public double Add(double n1, double n2)
     {
     return Convert.ToDouble(n1 + n2);
     }
    


    I built a manual HTTP POST in Fiddler using the following, but I received an HTTP 400 Bad Request error.

    POST http://localhost:9000/Calculator.svc/json/Add HTTP/1.1
    Host: localhost:9000
    Connection: keep-alive
    User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.107 Safari/535.1
    Accept: application/json; charset=utf-8
    Content-Type: json
    Content-Length: 34
    
    {"AddRequest" {"n1":1.0,"n2":2.0}}
    

    The server encountered an error processing the request. Please see the service help page for constructing valid requests to the service. The exception message is 'The incoming message has an unexpected message format 'Raw'. The expected message formats for the operation are 'Xml', 'Json'. This can be because a WebContentTypeMapper has not been configured on the binding.






    Friday, August 12, 2011 3:33 PM

Answers

  • Many questions in a single post :)

    1. I really don't want the MS AJAX wrapping around my JSON response objects.  Do I HAVE to use WebGet() in order to use more than 1 parameter with a POST operation?

    As Ido Flatow_ suggested, you can use WrappedRequest, and the response won't be wrapped.

    2. If I end up having to use a GET, would that change my url to something like this? http://localhost:9000/Calculator/Add?n1=1.0&n2=2.0

    Yes, that's correct.

    3. with the following jQuery?

    Since you're doing a GET request, you don't need to specify the contentType parameter. And since you already populated the query
    string parameters when creating myUrl, you don't need to pass a data parameter either.

    4. I also heard there was a way to use JSON in the query string. Something like this: ... Does it only work where the input parameters are
    complex data types like a Person (in above)?

    By default it only works with simple types. But you can add support for more types in the query string. The post
    at http://blogs.msdn.com/b/carlosfigueira/archive/2011/08/09/wcf-extensibility-querystringconverter.aspx shows how this can be done

    5.  I tried doing POST WebMessageBodyStyle.Wrapped combination but I was not too sure how the json request was supposed to be formatted

    The expected format is a JSON object with the keys being the parameter names: {"n1":1.0,"n2":2.0}


    Carlos Figueira
    Friday, August 12, 2011 4:10 PM
    Moderator

All replies

  • The bodyStyle parameter of WebInvoke can also be set for WrappedRequest, which will wrap the request but not the response. Did you try it?
    Please mark posts as answers/helpful if it answers your question.
    Senior Consultant on WCF, ASP.NET, Siverlight, and Entity Framework. Author of Microsoft's Official WCF 4 Course. Co-author of the Microsoft HPC/Azure burst whitepaper.
    Visit my blog: http://blogs.microsoft.co.il/blogs/idof
    Friday, August 12, 2011 3:59 PM
  • Many questions in a single post :)

    1. I really don't want the MS AJAX wrapping around my JSON response objects.  Do I HAVE to use WebGet() in order to use more than 1 parameter with a POST operation?

    As Ido Flatow_ suggested, you can use WrappedRequest, and the response won't be wrapped.

    2. If I end up having to use a GET, would that change my url to something like this? http://localhost:9000/Calculator/Add?n1=1.0&n2=2.0

    Yes, that's correct.

    3. with the following jQuery?

    Since you're doing a GET request, you don't need to specify the contentType parameter. And since you already populated the query
    string parameters when creating myUrl, you don't need to pass a data parameter either.

    4. I also heard there was a way to use JSON in the query string. Something like this: ... Does it only work where the input parameters are
    complex data types like a Person (in above)?

    By default it only works with simple types. But you can add support for more types in the query string. The post
    at http://blogs.msdn.com/b/carlosfigueira/archive/2011/08/09/wcf-extensibility-querystringconverter.aspx shows how this can be done

    5.  I tried doing POST WebMessageBodyStyle.Wrapped combination but I was not too sure how the json request was supposed to be formatted

    The expected format is a JSON object with the keys being the parameter names: {"n1":1.0,"n2":2.0}


    Carlos Figueira
    Friday, August 12, 2011 4:10 PM
    Moderator
  • Thanks for the quick responses.  I'm going to try and modify my service and I'll post again with the results.  Hopefully this gets me where I want to go.
    http://www.montavesta.net
    Friday, August 12, 2011 4:38 PM
  • Ok so I managed to get this working...sort of.  I changed my WebInvoke to use BodyStyle = WebMessageBodyStyle.WrappedRequest and that seemed to take care of the serialization of the POST message body.

    I modified my jQuery to:

     

      jQuery.support.cors = true;
      numLeft = $('#txtNumLeft').val();
      numRight = $('#txtNumRight').val();
      ajaxData = "{\"n1\":" + numLeft + ",\"n2\":" + numRight + "}"
    
      $.ajax({
       type: "POST",
       url: "http://localhost/Calculator/Calculator.svc/json/Add",
       data: ajaxData,
       contentType: "application/json; charset=utf-8",
       dataType: "json",
       success: function (msg) {
        $('#txtAnswer').val(msg);
       },
       error: function (request, status, error) {
        alert(status + ' : ' + error);
       }
      });
    

     

    (changed IIS hosting back to port 80)

    And this returned back a success.  So here's my remaining quirk, when jQuery does the HTTP POST request to the WCF Service, the following is generated in IE:

     

    POST http://localhost/Calculator/Calculator.svc/json/Add HTTP/1.1
    Content-Type: application/json; charset=utf-8
    Accept-Language: en-us
    Referer: http://localhost:29436/Default.aspx
    Accept: application/json, text/javascript, */*; q=0.01
    Accept-Encoding: gzip, deflate
    User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; GTB7.1; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.3)
    Host: localhost
    Content-Length: 15
    Connection: Keep-Alive
    Pragma: no-cache
    
    {"n1":1,"n2":2}
    

     

    Which looks correct.  However, when I run this in Chrome13 the following is generated over the wire:

     

    OPTIONS http://localhost/Calculator/Calculator.svc/json/Add HTTP/1.1
    Host: localhost
    Connection: keep-alive
    Referer: http://localhost:29436/Default.aspx
    Access-Control-Request-Method: POST
    Origin: http://localhost:29436
    User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1
    Access-Control-Request-Headers: Origin, Content-Type, Accept
    Accept: */*
    Accept-Encoding: gzip,deflate,sdch
    Accept-Language: en-US,en;q=0.8
    Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
    

     

    Obviously this is not going to return a result.  I have a feeling since I am not hosting the webPage using Local IIS but using the Visual Studio WebDev40.exe this is causing cross origin XHR issues.  The server hosts the page at http://localhost:29436/Default.aspx  I am guessing the different port throws off the origin.

    I even included: 

    jQuery.support.cors = true;  

    but this doesn't seem to be doing anything in Chrome.  I guess I can either host the WCF service on the same port as the web applications or look into JSONP again. 


    http://www.montavesta.net
    Friday, August 12, 2011 8:44 PM