locked
Calling WCF with BasicHttp using JQuery RRS feed

  • Question

  • Hi,

    I am trying to call a WCF service method exposed with basicHttp binding using Jquery. I am getting "Bad Request" error. I can sucessfully call the method if I expose it as REST service(webHttp binding).Could anyone help me 

    The code is as following:

     var theRequest = " \

    <s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"> \

    <s:Header> \

    <Action s:mustUnderstand=\"1\" xmlns=\"http://schemas.microsoft.com/ws/2005/05/addressing/none\">http://tempuri.org/IService1/GetData</Action> \

    </s:Header> \

    <s:Body> \

    <GetData xmlns=\"http://tempuri.org/\"> \

    <value>8</value> \

    </s:Body> \

    </s:Envelope>"

     

    ;

    $(document).ready(

    function

    () {

    $(

    "#btnWCFBasicHttp").click(function

    () {

    $.ajax({

    type:

    "POST"

    ,

    url:

    "http://localhost:1425/Service1.svc/bh/"

    ,

    data: theRequest,

    timeout: 10000,

    contentType:

    "text/xml"

    ,

    dataType:

    "xml"

    ,

    beforeSend:

    function

    (xhr) {

    xhr.setRequestHeader(

    "SOAPAction", "http://tempuri.org/IService1/GetData"

    );

    },

    async:

    false

    ,

    success:

    function

    (data) {

    alert(data)

    },

    error:

    function

    (xhr, status, error) {

    alert(error);

    }

    });

    });

    });

    Also, how I can call WCF service method using JQuery which has been exposed using

    "wsHttp" binding? Is it possible ?

    Thanks in advance.

    ronit_rc

    Friday, December 30, 2011 11:25 AM

Answers

All replies

  • Yes, you can use jQuery to do that, but you'll need to format the request exactly as a WCF client would do. One easy way to verify that is to create one such a client (e.g. using svcutil to create a proxy), send a request using that proxy to the server and capture that using a tool such as fiddler. Then you'd capture what the jQuery page is sending, then compare with the one sent by the WCF client.

    Below is an example of a basicHttpBinding service which can be called by jQuery.

    Post_ca5941b4_bfcf_4546_a418_cc91a321c2fb.svc:

    <%@ ServiceHost Language="C#" Debug="true" Service="Post_ca5941b4_bfcf_4546_a418_cc91a321c2fb.Service1" CodeBehind="Post_ca5941b4_bfcf_4546_a418_cc91a321c2fb.svc.cs" %>
    

    Post_ca5941b4_bfcf_4546_a418_cc91a321c2fb.svc.cs:

    namespace Post_ca5941b4_bfcf_4546_a418_cc91a321c2fb
    {
        [ServiceContract]
        public interface IService1
        {
            [OperationContract]
            int Add(int x, int y);
        }
        public class Service1 : IService1
        {
            public int Add(int x, int y)
            {
                return x + y;
            }
        }
    }
    
    

    Web.config:

      <system.serviceModel>
        <behaviors>
          <serviceBehaviors>
            <behavior name="">
              <serviceMetadata httpGetEnabled="true" />
              <serviceDebug includeExceptionDetailInFaults="false" />
            </behavior>
          </serviceBehaviors>
        </behaviors>
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
        <services>
          <service name="Post_ca5941b4_bfcf_4546_a418_cc91a321c2fb.Service1">
            <endpoint address=""
                      binding="basicHttpBinding"
                      contract="Post_ca5941b4_bfcf_4546_a418_cc91a321c2fb.IService1"/>
          </service>
        </services>
      </system.serviceModel>
    
    

    JavaScript code:

            function Post_ca5941b4_bfcf_4546_a418_cc91a321c2fb() {
                var url = "/Post_ca5941b4_bfcf_4546_a418_cc91a321c2fb.svc";
                var request = "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
                        "<s:Body>" +
                            "<Add xmlns=\"http://tempuri.org/\">" +
                                "<x>5</x><y>7</y>" +
                            "</Add>" +
                        "</s:Body>" +
                    "</s:Envelope>";
                $.ajax({
                    type: "POST",
                    url: url,
                    data: request,
                    contentType: "text/xml",
                    beforeSend: function (xhr) {
                        xhr.setRequestHeader(
                            "SOAPAction",
                            "http://tempuri.org/IService1/Add");
                    },
                    success: function (data, textStatus, jqXHR) {
                        $("#result").text(jqXHR.responseText);
                    },
                    error: function (jqXHR, textStatus, errorThrown) {
                        $("#result").text("error");
                    }
                });
            }
    
    


    Carlos Figueira
    Friday, December 30, 2011 3:44 PM
  •  

    Hi Carlos,

    Thanks for the answer!

    Actually I have taken the SOAP request from  WCF Test client on calling the method. Could you please look into my code. I cannot understand what I am doing wrong.

    Also, can I call a WCF service using JQuery which has been exposed with "wsHttp" binidng?

    Regards

    ronit_rc

     

    Saturday, December 31, 2011 1:55 PM
  • The code seems fine, but without having the complete picture (svc, config, service code) it's hard to tell. Try comparing what jQuery is sending to what WCF Test Client sends to the request - HTTP headers, body, and see if there is anything different.

    And yes, it's possible to call a wsHttpBinding-endpoint as well. As far as the server is concerned, it's just a HTTP request coming over the wire, it doesn't matter whether it's coming from a "real" WCF client, jQuery, or someone with a plain socket connection. It's going to be harder to create the request, though, as wsHttp requires a lot more data to be sent (in terms of SOAP headers). And if the binding uses security, it's going to be even harder.

    Also, try enabling tracing at the server side; it should tell why the server is rejecting your request and give more information about what can be changed.


    Carlos Figueira
    Saturday, December 31, 2011 3:57 PM
  •  

    Hi Carlos,

    Thanks for your response.

    Finally I noticed the mistake. I missed the </GetData> element in the SOAP request. Now my JQuery code is gracefully calling the WCF sevice exposed with "basisHttp" binding.

    Now, I am trying to call WCF sevice exposed with "wsBasisHttp" binding. I am getting (415  - Unsupported Media Type Error) error. Could you please help me on resolving this?

    The SOAP request for the service is as following:

    var whRequest ="<s:Envelope xmlns:a=\"http://www.w3.org/2005/08/addressing\" xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\">" +
                              "<s:Header>" +
                              "<a:Action s:mustUnderstand=\"1\">http://tempuri.org/IService1/GetData</a:Action>" +
                              "<a:MessageID>urn:uuid:7fdde7b6-64c8-4402-9af1-cc848f15888f</a:MessageID>" +
                              "<a:ReplyTo>" +
                              "<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>" +
                              "</a:ReplyTo>" +
                              "</s:Header>" +
                              "<s:Body>" +
                              "<GetData xmlns=\"http://tempuri.org/\">"+
                              "<value>9</value>"+
                              "</GetData>" +
                              "</s:Body>" +
                              "</s:Envelope>";

              $(document).ready(function () {
                  $("#btnWCFWSHttp").click(function () {
                      $.ajax({
                          type: "POST",
                          url: "http://localhost:3581/Service1.svc/wh/",
                          data: whRequest,
                          timeout: 10000,
                          contentType: "text/xml",
                          dataType: "xml",
                          beforeSend: function (xhr) {
                              xhr.setRequestHeader("SOAPAction", "http://tempuri.org/IService1/GetData");
                          },
                          async: false,
                          success: function (data) {
                                $(data).find("GetDataResponse").each(function () {
                                  alert($(this).find("GetDataResult").text());
                              });
                          },
                          error: function (xhr, status, error) {
                              alert(error);

                          }
                      });
                  });
              });

    Regards

    ronit_rc


    Monday, January 2, 2012 9:37 AM
  • The SOAP request for a wsHttpBinding endpoint is different than the one for a basicHttpBinding - you'll need to again capture the request sent from a "real" WCF client (such as the WCF Test Client), then create a request which is similar to that one. The code below works for my service, but you'll need to see what needs to be sent to yours.

    A few things I noticed are incorrect in your client code is that the content-type for SOAP 1.2 (which is what wsHttpBinding uses) is application/soap+xml, not text/xml (that's the actual cause of your 415 error); the SOAP header needs a "To" header with addressing information for the endpoint. Maybe there are more, you can check by comparing the two requests.

            function Post_ca5941b4_bfcf_4546_a418_cc91a321c2fb_WS() {
                var url = "/Post_ca5941b4_bfcf_4546_a418_cc91a321c2fb.svc/ws";
                var request = "<s:Envelope " +
            "xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\" " +
            "xmlns:a=\"http://www.w3.org/2005/08/addressing\">" +
        "<s:Header>" +
            "<a:Action s:mustUnderstand=\"1\">http://tempuri.org/IService1/Add</a:Action>" +
            "<a:MessageID>urn:uuid:9cc71731-811b-4baa-9db3-e6faa9a1c347</a:MessageID>" +
            "<a:ReplyTo><a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address></a:ReplyTo>" +
            "<a:To s:mustUnderstand=\"1\">http://localhost:17660/Post_ca5941b4_bfcf_4546_a418_cc91a321c2fb.svc/ws</a:To>" +
        "</s:Header>" +
        "<s:Body>" +
            "<Add xmlns=\"http://tempuri.org/\">" +
                "<x>44</x>" +
                "<y>55</y>" +
            "</Add>" +
        "</s:Body>" +
    "</s:Envelope>";
                $.ajax({
                    type: "POST",
                    url: url,
                    data: request,
                    contentType: "application/soap+xml",
                    success: function (data, textStatus, jqXHR) {
                        $("#result").text(jqXHR.responseText);
                    },
                    error: function (jqXHR, textStatus, errorThrown) {
                        $("#result").text("error");
                    }
                });
            }
    
    


    Carlos Figueira
    Monday, January 2, 2012 3:10 PM
  •  

    Hi Calos,

    Thanks again for your help.

    I have rectified the content type to "application/soap/xml" and added the"To" header with addressing information for the endpoint. Now there is no (415  - Unsupported Media Type Error) error. But I am getting a "undefined" error with the following responsetext:

    "<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing"><s:Header><a:Action s:mustUnderstand="1">http://www.w3.org/2005/08/addressing/soap/fault</a:Action><a:RelatesTo>urn:uuid:7fdde7b6-64c8-4402-9af1-cc848f15888f</a:RelatesTo></s:Header><s:Body><s:Fault><s:Code><s:Value>s:Sender</s:Value><s:Subcode><s:Value xmlns:a="http://schemas.xmlsoap.org/ws/2005/02/sc">a:BadContextToken</s:Value></s:Subcode></s:Code><s:Reason><s:Text xml:lang="en-GB">The message could not be processed. This is most likely because the action 'http://tempuri.org/IService1/GetData' is incorrect or because the message contains an invalid or expired security context token or because there is a mismatch between bindings. The security context token would be invalid if the service aborted the channel due to inactivity. To prevent the service from aborting idle sessions prematurely increase the Receive timeout on the service endpoint's binding.</s:Text></s:Reason></s:Fault></s:Body></s:Envelope>"                                                                                                                                       

    There should not be any problem with the action, since using the same action I can call the service method exposed by "basicHttp" binding.

    Modified SOAP Request

    "<s:Envelope xmlns:a=\"http://www.w3.org/2005/08/addressing\" xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\">" +
                              "<s:Header>" +
                              "<a:Action s:mustUnderstand=\"1\">http://tempuri.org/IService1/GetData</a:Action>" +
                              "<a:MessageID>urn:uuid:7fdde7b6-64c8-4402-9af1-cc848f15888f</a:MessageID>" +
                              "<a:ReplyTo>" +
                              "<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>" +
                              "</a:ReplyTo>" +
                              "<a:To s:mustUnderstand=\"1\">http://localhost:3581/Service1.svc/wh</a:To>" +
                              "</s:Header>" +
                              "<s:Body>" +
                              "<GetData xmlns=\"http://tempuri.org/\">"+
                              "<value>9</value>"+
                              "</GetData>" +
                              "</s:Body>" +
                              "</s:Envelope>";

    You are helping me a lot. Could you please help me in resolving the problem?

    Regards

    ronit_rc

     

    Tuesday, January 3, 2012 5:27 AM
  • As I mentioned, you need to compare what is sent to your service by the WCF test client. One thing which may be happening is that if the binding uses security (which is the default for wsHttpBinding), then this request will be rejected (you need to either disable security or to actually handle the handshake in the jQuery code itself, which will be really hard.
    Carlos Figueira
    Tuesday, January 3, 2012 5:30 AM
  •  

    Hi Carlos,

    Thanks for the answer.

    I have compared the requests once again but didn't found any difference.

    Earlier you had provided an example where you sucessfully called the "wsHttp" binded WCF service in JQuery. Did you disabled security at WCF service end? Also is there any example where WCF security has been handled in JQuery?

    Thanks in advance.

    Regards

    ronit_rc

     

     


    • Edited by ronit_rc Tuesday, January 3, 2012 7:17 AM
    Tuesday, January 3, 2012 7:17 AM
  • ronit_rc, there has to be a difference between the request you send with jQuery and the request you send with the WCF Test Client. Make sure you're talking to the same endpoint with the test client (same HTTP headers, address). As far as the WCF service is concerned, the requests are simply bytes coming over a TCP port, and it doesn't make any distinction between a "normal" WCF client or any other client (such as jQuery).

    In my example, I did disable security at the WCF service, if you want to use that request I sent you'll need to do that as well. I don't think there is any example where WS-Security is implemented using jQuery, because it uses some encryption algorithms which AFAIK aren't available in javascript.


    Carlos Figueira
    Tuesday, January 3, 2012 5:05 PM
  • Hi Calrlos,

    I think, I should give a try by disabling security in WCF service. How I can disable security at the WCF service?

    Regards

    ronit_rc

    Tuesday, January 3, 2012 6:42 PM
  • Take a look at the code for this post at https://github.com/carlosfigueira/WCFQuickSamples/tree/master/WCFForums/QuickWebCode1. The web.config has a <binding> element for wsHttpBinding which disables security.
    Carlos Figueira
    • Marked as answer by ronit_rc Wednesday, January 4, 2012 12:03 PM
    Tuesday, January 3, 2012 7:38 PM
  • Hi Carlos,

    Finally I succeeded to call the "wsHttp" binded WCF service method after disabling the security as service end. So, as I can understand, I have to compromise with security, if I want to call a "wsHttp" binded WCF service method  in JQuery.

    One thing I have noticed, a "wsHttp" response cannot be parsed with "jquery-1.4.1.min.js". It parses a blank responseXML and results a "parsererror" although there is valid "responseText". You need to use "jquery-1.5.1.min.js" onwards in oredr to parse "wsHttp" response.

    Thanks a lot for the help and getting the things done.

     

    Regards

    ronit_rc


    • Edited by ronit_rc Wednesday, January 4, 2012 12:21 PM
    Wednesday, January 4, 2012 12:20 PM