Wednesday, July 19, 2017

How to call a WCF service from javascript?

Leave a Comment

I'm trying to call a WCF service from an ajax call with jQuery. I manage to call the WCF from SOAP-UI and from Excel/VBA. My problem comes from the OPTIONS request that's sent and no POST follows:

  • if I set URL to http://mywcf/service.svc, OPTIONS is sent and I get a 400 Bad Request status and POST request is not sent. In this case, there's missing HTTP/1.1 in header (comparing with SOAP-UI headers).
  • if I set URL to http://mywcf/service.svc HTTP/1.1, OPTIONS is sent and I get a 200 OK status but POST request is not sent. In this case, HTTP/1.1 seems to be interpreted as a filename.

Can someone tell me how to call a POST action on a WCF from javascript and to add HTTP/1.1 header without corrupting service URL?

Here is a extract from my ajax call:

var soapData = ''         +'<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:mic="http://microsoft.wcf.documentation">'         +'    <soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:wsrm="http://docs.oasis-open.org/ws-rx/wsrm/200702">'         +'        <wsrm:Sequence>'         +'            <wsrm:Identifier>s:Sender a:ActionNotSupported</wsrm:Identifier>'         +'            <wsrm:MessageNumber>1</wsrm:MessageNumber>'         +'        </wsrm:Sequence>'         +'        <wsa:Action>http://schemas.xmlsoap.org/ws/2005/02/rm/CreateSequence</wsa:Action>'         +'        <wsa:ReplyTo>'         +'            <wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>'         +'        </wsa:ReplyTo>'         +'        <wsa:MessageID>uuid:'+ MsgUid +'</wsa:MessageID>'         +'        <wsa:To>'+ Url +'</wsa:To>'         +'    </soap:Header>'         +'    <soap:Body xmlns:wsrm="http://schemas.xmlsoap.org/ws/2005/02/rm">'         +'        <wsrm:CreateSequence>'         +'            <wsrm:AcksTo xmlns:wsa="http://www.w3.org/2005/08/addressing">'         +'                <wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>'         +'            </wsrm:AcksTo>'         +'            <wsrm:Offer>'         +'                <wsrm:Identifier>urn:soapui:'+ SeqUid +'</wsrm:Identifier>'         +'            </wsrm:Offer>'         +'        </wsrm:CreateSequence>'         +'    </soap:Body>'         +'</soap:Envelope>';  $.ajax({     type: 'POST',     url: 'http://mywcf/service.svc', // with or without +' HTTP/1.1'     data: soapData,     contentType: 'application/soap+xml;charset=UTF-8',     dataType: 'xml' }); 

Values in my WCF web.config:

<system.webServer>     <httpProtocol>         <customHeaders>             <add name="Access-Control-Allow-Origin" value="*" />             <add name="Access-Control-Allow-Methods" value="POST, OPTIONS" />             <add name="Access-Control-Allow-Headers" value="*" />         </customHeaders>     </httpProtocol> </system.webServer> 

3 Answers

Answers 1

To consume a web service using jQuery, that is to make a call to the WCF service, you either use jQuery.ajax() or jQuery.getJSON(). In this article I used the jQuery.ajax()method.

To set the request, first define a variable. This will be helpful when you are calling multiple methods and creating a different js file to call the WCF service.

<script type="text/javascript">      var Type;     var Url;     var Data;     var ContentType;     var DataType;     var ProcessData; 

The following function initializes variables which are defined above to make a call to the service.

function WCFJSON() {     var userid = "1";     Type = "POST";     Url = "Service.svc/GetUser";     Data = '{"Id": "' + userid + '"}';     ContentType = "application/json; charset=utf-8";     DataType = "json"; varProcessData = true;      CallService(); } 

The CallService function sends requests to the service by setting data in $.ajax.

// Function to call WCF  Service        function CallService() {     $.ajax({         type: Type, //GET or POST or PUT or DELETE verb         url: Url, // Location of the service         data: Data, //Data sent to server         contentType: ContentType, // content type sent to server         dataType: DataType, //Expected data format from server         processdata: ProcessData, //True or False         success: function(msg) {//On Successfull service call             ServiceSucceeded(msg);         },         error: ServiceFailed// When Service call fails     }); }  function ServiceFailed(result) {     alert('Service call failed: ' + result.status + '' + result.statusText);     Type = null;     varUrl = null;     Data = null;      ContentType = null;     DataType = null;     ProcessData = null; } 

Note: The following code checks the result.GetUserResult statement, so your result object gets the property your service method name + Result. Otherwise, it will give an error like object not found in Javascript.

function ServiceSucceeded(result) {     if (DataType == "json") {         resultObject = result.GetUserResult;          for (i = 0; i < resultObject.length; i++) {             alert(resultObject[i]);         }      }  }  function ServiceFailed(xhr) {     alert(xhr.responseText);      if (xhr.responseText) {         var err = xhr.responseText;         if (err)             error(err);         else             error({ Message: "Unknown server error." })     }      return; }  $(document).ready(     function() {         WCFJSON();     } ); </script> 

Answers 2

Add webHttpBinding endpoint

    <services>   <service name="Contract">     <endpoint address="json" binding="webHttpBinding"  contract="IContract" bindingConfiguration="ActionsHttpBinding" behaviorConfiguration="ActionrestfulBehavior"/>   </service> 

then call the endpoint from ajax as post or get, see below example :

    var data = JSON.stringify({     param1: val1,     param2: val2 }); $.ajax({     url: "http://mywcf/service.svc/json/FunctionName",     type: "POST",     data: data,     contentType: "application/json; charset=utf-8",     dataType: "json",     processData: true }).then(function (rsutlt) {  }).fail(function (fail) { }); 

Answers 3

Add below code to your global.asax.cs, and remove customHeaders from your web config.

protected void Application_BeginRequest(object sender, EventArgs e)     {         HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");          if (HttpContext.Current.Request.HttpMethod == "OPTIONS")         {             //These headers are handling the "pre-flight" OPTIONS call sent by the browser             HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");             HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");             HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");             HttpContext.Current.Response.End();         }      } 

Also you need remove OPTIONSVerbHandler for enabling cors.

 <system.webServer>     <validation validateIntegratedModeConfiguration="false" />     <handlers>       <remove name="ExtensionlessUrlHandler-Integrated-4.0" />       <remove name="OPTIONSVerbHandler" />       <remove name="TRACEVerbHandler" />       <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />     </handlers> </system.webServer> 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment