Showing posts with label wsdl. Show all posts
Showing posts with label wsdl. Show all posts

Tuesday, May 29, 2018

javascript and web services WSDL

Leave a Comment

i want to call a web service using javascript. i have a form where i give some parameters (int) and want to get the result how can do it using javascript?

here are the WSDL files

<definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://lapack.sws4hpsc.uth/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://lapack.sws4hpsc.uth/" name="DgesvSampleWsService"> <ns1:Policy xmlns:ns1="http://www.w3.org/ns/ws-policy" wsu:Id="DgesvSampleWsPortBinding_MTOM_Policy"> <ns1:ExactlyOne> <ns1:All> <ns2:OptimizedMimeSerialization xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/09/policy/optimizedmimeserialization" ns1:Optional="true"/> </ns1:All> </ns1:ExactlyOne> </ns1:Policy> <types> <xsd:schema> <xsd:import namespace="http://lapack.sws4hpsc.uth/" schemaLocation="http://83.212.96.238:8080/DgesvSampleWs/DgesvSampleWsService?xsd=1"/> </xsd:schema> </types> <message name="_dgesv"> <part name="parameters" element="tns:_dgesv"/> </message> <message name="_dgesvResponse"> <part name="parameters" element="tns:_dgesvResponse"/> </message> <portType name="DgesvSampleWs"> <operation name="_dgesv"> <input message="tns:_dgesv"/> <output message="tns:_dgesvResponse"/> </operation> </portType> <binding name="DgesvSampleWsPortBinding" type="tns:DgesvSampleWs"> <ns3:PolicyReference xmlns:ns3="http://www.w3.org/ns/ws-policy" URI="#DgesvSampleWsPortBinding_MTOM_Policy"/> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/> <operation name="_dgesv"> <soap:operation soapAction=""/> <input> <soap:body use="literal"/> </input> <output> <soap:body use="literal"/> </output> </operation> </binding> <service name="DgesvSampleWsService"> <port name="DgesvSampleWsPort" binding="tns:DgesvSampleWsPortBinding"> <soap:address location="http://83.212.96.238:8080/DgesvSampleWs/DgesvSampleWsService"/> </port> </service> </definitions> 

and the second one

<definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://lapack.sws4hpsc.uth/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://lapack.sws4hpsc.uth/" name="DgtsvSampleWsService"> <ns1:Policy xmlns:ns1="http://www.w3.org/ns/ws-policy" wsu:Id="DgtsvSampleWsPortBinding_MTOM_Policy"> <ns1:ExactlyOne> <ns1:All> <ns2:OptimizedMimeSerialization xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/09/policy/optimizedmimeserialization" ns1:Optional="true"/> </ns1:All> </ns1:ExactlyOne> </ns1:Policy> <types> <xsd:schema> <xsd:import namespace="http://lapack.sws4hpsc.uth/" schemaLocation="http://83.212.96.238:8080/DgtsvSampleWs/DgtsvSampleWsService?xsd=1"/> </xsd:schema> </types> <message name="_dgtsv"> <part name="parameters" element="tns:_dgtsv"/> </message> <message name="_dgtsvResponse"> <part name="parameters" element="tns:_dgtsvResponse"/> </message> <portType name="DgtsvSampleWs"> <operation name="_dgtsv"> <input message="tns:_dgtsv"/> <output message="tns:_dgtsvResponse"/> </operation> </portType> <binding name="DgtsvSampleWsPortBinding" type="tns:DgtsvSampleWs"> <ns3:PolicyReference xmlns:ns3="http://www.w3.org/ns/ws-policy" URI="#DgtsvSampleWsPortBinding_MTOM_Policy"/> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/> <operation name="_dgtsv"> <soap:operation soapAction=""/> <input> <soap:body use="literal"/> </input> <output> <soap:body use="literal"/> </output> </operation> </binding> <service name="DgtsvSampleWsService"> <port name="DgtsvSampleWsPort" binding="tns:DgtsvSampleWsPortBinding"> <soap:address location="http://83.212.96.238:8080/DgtsvSampleWs/DgtsvSampleWsService"/> </port> </service> </definitions> 

3 Answers

Answers 1

  1. Create a SOAP request and invoke the caller. ref: Simplest SOAP example

  2. Get the response and parse the XML. ref: Parse XML using JavaScript

Answers 2

here you go, using jquery:

 $.ajax({     type: 'POST',     url: '/your-web-service-path.asmx/your-method-name',     data: {yourparam: 1}      dataType: 'json',     contentType: 'application/json; charset=utf-8',     success: function(r){},     error: function(e){}  }); 

Answers 3

Here a possible approach, assuming you put wsdl into a file request.wsdl and assuming that the remote server is accessible and have Access-Control-Allow-Origin: * header

//wsdl request var client = new XMLHttpRequest(); client.open('GET', 'request.wsdl'); client.onreadystatechange = function () {   var request = client.responseText;//here the wsdl          //SOAP request         var client2 = new XMLHttpRequest();         client2.open('POST', 'http://83.212.96.238:8080/DgesvSampleWs/DgesvSampleWsService', true);          client2.onreadystatechange = function () {           if (client2.readyState == 4) {             if (client2.status == 200) {               console.log(client.responseText);//here the response             }           }         }         client2.setRequestHeader('Content-Type', 'text/xml');         client2.send(request); }  client.send(); 

The idea is performing and ajax to call wsdl definitions and in it's callback, perform another ajax that call that you want to call. This domains http://83.212.96.238:808 it's not giving me response but I think the approach is valid.

Read More

Monday, April 30, 2018

PHP soap issues

Leave a Comment

Drupal 7-soap

This is the error which iam getting in error log and when iam trying to print the test.wsdl file

SoapFault: looks like we got no XML document in SoapClient->__call() 

enter image description here

I have no clue what is the error

My project environment

PHP : 5.4.11

MySQL : 5.5.27 Apache : 2.2.3

OS : CentOS 5.8

code information

function ai_server() {   ini_set('soap.wsdl_cache_ttl', 0);   $server = new SoapServer(file_create_url(variable_get('app_integration_wsdl')), array("trace" => 1, "exceptions" => 0));   $server->addFunction('getData');   $server->addFunction('getId');   $server->addFunction('getInfo');   $server->addFunction('getrightsInfo');   $server->addFunction('updateInfo');   $server->addFunction('resetAppHistory');   //$server->addFunction('resetAppId');    $server->handle(); } 

soap client

function ai_sync_test() {   ini_set('soap.wsdl_cache_ttl', 0); // // ---------------------------------------------------------------- basic tests //    // is settings file accessible   $settings_file = variable_get('app_integration_settings');   require_once($settings_file);   $settings_output = is_readable($settings_file) ? 'Ok! Settings file is readable.' : 'Error! Not readable or accessible.';    // is wsdl file accessible   $wsdl_file = variable_get('app_integration_wsdl');   $wsdl_output = is_readable($wsdl_file) ? 'Ok! WSDL file is readable. ' . l('Open it. ', $wsdl_file, array('attributes' => array('target' => '_blank'))) : 'Error! Not readable or accessible. ';   $wsdl_output .= 'You need to define domain name in it into this sections (at the bottom of app_integration.wsdl file): ';   $wsdl_output .= htmlentities('<soap:address location="http://YOUR_DOMAIN_HERE/app_integration/server"/>');    // methods, which integration service is provide   $client = new SoapClient($wsdl_file, array("trace" => 1, "exceptions" => 0));    $methods = $client->__getFunctions();   $methods_output = '';   foreach ($methods as $method) {     $methods_output .= '<li>' . $method . '</li>';   } 

1 Answers

Answers 1

2 possible reasons -

  1. You are echoing something in the code, or whitespace characters are getting printed or trailing new line character.

  2. The server SOAP file in php has encode utf8 with BOM, causing apache send back the BOM mark (3 bytes) before the xml response. Encode your php file soap server with utf8 WITH OUT BOM mark.

function strip_bom($str){     return preg_replace( '/^(\x00\x00\xFE\xFF|\xFF\xFE\x00\x00|\xFE\xFF|\xFF\xFE|\xEF\xBB\xBF)/', "", $str ); } 
Read More

Sunday, November 19, 2017

Soap Client Complex Type PHP Request

Leave a Comment

I have a web-service with following link I'm trying to access the function name with SubmitRequestType but it seems the function is not exist instead submitAnsiSingle this is the correct function name what I tried so far is ,

$wsdl = 'https://ww3.navicure.com:7000/webservices/NavicureSubmissionService?WSDL';  class SecurityHeaderType {         private $submitterIdentifier;         private $originatingIdentifier;         private $submitterPassword;         private $submissionId;         function SecurityHeaderType() {             $this->submitterIdentifier = '***';             $this->originatingIdentifier = '****';             $this->submitterPassword = '****';             $this->submissionId = '';          }            }  class SubmitRequestType {          private $submitterIdentifier;         private $originatingIdentifier;         private $submitterPassword;         private $submissionId;         private $timeout;         private $transactionType;         private $submittedAnsiVersion;         private $resultAnsiVersion;         private $submitterSubmissionId;         private $processingOption;         private $payload;         private $exceptions;          function SubmitRequestType() {          $this->submitterIdentifier = '***';         $this->originatingIdentifier = '***';         $this->submitterPassword = '**';         $this->submissionId = '**';         $this->timeout = 60 ;         $this->transactionType = "E";         $this->submittedAnsiVersion = '5010';         $this->resultAnsiVersion = '5010';         $this->submitterSubmissionId = '**';         $this->processingOption = 'R';         $this->payload = 'EDI-270-Request';         $this->exceptions = true;         } }  $soapheader = new SecurityHeaderType();   $submitrequest = new SubmitRequestType();        $service = new \SoapClient($wsdl);     $result= $service->SubmitAnsiSingle($submitrequest);     echo "<pre/>";print_r($result);      $types = $service->__getTypes ();     $functions = $service->__getFunctions ();     //echo "<pre/>";print_r($types);     //echo "<pre/>";print_r($functions); 

But I'm getting the response like below it seems the request is processing on their end but the SecurityHeaderType is not parsing their end.

stdClass Object (     [transactionTyp] => E     [submitterSubmissionId] => ****     [submittedAnsiVersion] => 5010     [resultAnsiVersion] => 5010     [statusHeader] => stdClass Object         (             [statusCode] => 1150             [statusMessage] => com.navicure.webservices.core.WSCoreException: Account does not exist for ''             [requestProcessed] =>          )  ) 

Any hint will be highly appreciate

Thanks in advance.

2 Answers

Answers 1

I found the solution!. It seems the PHP -> .NET web service comparability issue. So from PHP the complex type SOAP (this kind of format) can't access I found some usefull post here. So I switched SOAP to plain XML request with CURL and it seems working fine!. Also from WSDL link we can extract the request template using this online service . So my final code look like below.

$xml_data = "<?xml version='1.0' encoding='UTF-8'?> <s12:Envelope xmlns:s12='http://www.w3.org/2003/05/soap-envelope'>   <s12:Header>     <ns1:SecurityHeaderElement xmlns:ns1='http://www.navicure.com/2009/11/NavicureSubmissionService'>       <ns1:originatingIdentifier>****</ns1:originatingIdentifier>       <ns1:submitterIdentifier>****</ns1:submitterIdentifier>       <ns1:submitterPassword>***</ns1:submitterPassword>       <ns1:submissionId>?999?</ns1:submissionId>     </ns1:SecurityHeaderElement>   </s12:Header>   <s12:Body>     <ns1:SubmitAnsiSingleRequestElement xmlns:ns1='http://www.navicure.com/2009/11/NavicureSubmissionService'>       <ns1:timeout>60</ns1:timeout>       <ns1:transactionType>E</ns1:transactionType>       <ns1:submittedAnsiVersion>5010</ns1:submittedAnsiVersion>       <ns1:resultAnsiVersion>5010</ns1:resultAnsiVersion>       <ns1:submitterSubmissionId></ns1:submitterSubmissionId>       <ns1:processingOption>R</ns1:processingOption>       <ns1:payload>EDI270Payload</ns1:payload>     </ns1:SubmitAnsiSingleRequestElement>   </s12:Body> </s12:Envelope>"; $URL = "https://ww3.navicure.com:7000/webservices/NavicureSubmissionService";  $ch = curl_init($URL); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml')); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, "$xml_data"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $output = curl_exec($ch); curl_close($ch);   print_r($output); 

Hope this will help someone else in future.

Answers 2

You might be running into PHP's slightly less than compatible WSDL2 implementation. You could try the following and cross your fingers;

Headerbody needs to be implemented in the same depth as defined in xml, since I do not have access to navicure's documentation here's example code:

$headerbody = array('Token' => $someToken,                      'Version' => $someVersion,                      'UserCredentials'=>array('UserID'=>$UserID,                                               'Password'=>$Pwd));   //Create Soap Header.         $header = new SOAPHeader($namespace, 'RequestorCredentials', $headerbody);   

// In case multiple headers are required, create $headers[] = $header, and append to headers after.

$options = array(         'uri'=>'http://schemas.xmlsoap.org/soap/envelope/',         'style'=>SOAP_RPC,         'use'=>SOAP_ENCODED,         'soap_version'=>SOAP_1_1,         'cache_wsdl'=>WSDL_CACHE_NONE,         'connection_timeout'=>15,         'trace'=>true,         'encoding'=>'UTF-8',         'exceptions'=>true,     ); try {     $soap = new SoapClient($wsdl, $options);     $soap->__setSoapHeaders($header);     $data = $soap->SubmitAnsiSingle(array($submitrequest)); } catch(Exception $e) {     die($e->getMessage()); } 

Hope this is of any use - in case WSDL2 is actually used you might be able to get it to work with nusoap which can be found on sourceforge. Although that hasn't been updated in quite a while..

Read More

Tuesday, September 26, 2017

Java WSDL modify or hide certain properties on Web View

Leave a Comment

TLDR Is it possible to create an "alias" for the IP address (such as 0.0.0.0:8080/services as SERVER_1) or any other property on the WSDL content while someone's reading it? Similar to:

<entry key="org.apache.cxf.endpoint.private" value="true"/> 

For the services list, that keeps the functionality intact but hides the services list.

If yes, how? If not, is there a way to hide it without using @XmlTransient because if we used it, and from my understanding, the program wouldn't even map this element and thus no longer work.


I'm working with SOAP services using Spring and JAX-RS.

We're securing our apps, after an ethical hacking test, the results thrown that we were exposing services and production IP addresses on our URLs.

We were able to hide the services list from the web view, for example, if we access http://localhost:8080/foo/services we get this text:

No services have been found. 

Which is fine and we've done it by following this answer, but instead of being on cxf-servlet.xml file, it was on the applicationContext-{moduleName}.xml file.

Now, if we know, or have access to any of the WSDL paths, we can still see the WSDL contents (which includes production IP addresses), for example if we entered:

http://localhost:8080/foo/services/bar?_wsdl 

We have a similar definition as below (I edited it for security reasons):

<application     xmlns="http://wsdl.dev.java.net/2009/02"     xmlns:xs="http://www.w3.org/2001/XMLSchema">     <grammars/>     <resources base="http://localhost:8080/foo/services/bar">         <resource path="/VX">             <resource path="/anotherPath">                 <method name="POST">                     <request>                         <representation mediaType="application/x-www-form-urlencoded">                             <param name="someParam" style="query" type="xs:string"/>                         </representation>                     </request>                     <response>                         <representation mediaType="application/json">                             <param name="anotherParam" style="plain" type="xs:string"/>                         </representation>                     </response>                 </method>             </resource>         </resource>     </resources> </application> 

How could I, for example edit on run time the property

<resources base="http://localhost:8080/foo/services/bar"> 

To something like

<resources base="SERVER_1"> 

So, we internally know what IP address does SERVER_1 has, but people outside that manage to get there doesn't, in other words how could I create an alias for the IP address and use it instead of the real ip address on it?

This is because we have about 10 servers, each with a different IP address, and if we need to do some production debugging we need to know which server we're in, so we would like to avoid hiding the whole WSDL content (as I know it can be done, because a module has this configuration).

I know I can use @XmlTransient annotation, but as per docs:

Prevents the mapping of a JavaBean property/type to XML representation.

So, in my understanding, if I use this annotation over the property containing the IP address, then it would no longer be working.

If this isn't possible, which other suggestions would you have in order to make a workaround for this particular case?

We create the services with top-down approach (i.e. we're given the WSDL and we use wsdl2java to create Java Objects + service interface from it)

1 Answers

Answers 1

TLDR: Use DNS to assign names to your IP addresses.

We're securing our apps, after an ethical hacking test, the results thrown that we were exposing services and production IP addresses on our URLs

You have a SOAP-Service. To use it one needs to know the address of the endpoint. So you'll "expose" it no matter what. Security through obscurity is not recommended.

So, we internally know what IP address does SERVER_1 has, but people outside that manage to get there doesn't, in other words how could I create an alias for the IP address and use it instead of the real ip address on it?

That's what DNS was invented for. An "alias" for the IP address. It's bad practise to use IP-Addresses for services. So set up a DNS (or use host files) to assign a name per IP address.

Read More

Thursday, September 14, 2017

PHP SoapClient returns null even thought there was a response

Leave a Comment

Using the PHP SoapClient, I make a call to the WSDL at https://webservices-test.ede.de:9443/ibis/ws/WS_EXT_ELC?wsdl and I get the following xml response (as indicated by $soapclient->__last_response)

<?xml version='1.0' encoding='UTF-8'?><soap:Envelope xmlns:ede="http://ede.de/webservices" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:soap="http://www.w3.org/2003/05/soap-envelope"><soap:Body><Response action="ELC" requestId="1" version="1.0"><created>2017-09-04T16:04:46.556+02:00</created><StatusInformation>OK</StatusInformation><StatusCode>0</StatusCode><Payload><SalesOrderSimulateConfirmation><Items><Item><ID>10</ID><ProductID>0003062700050</ProductID><Price>2.970</Price><PositionPrice>2.970</PositionPrice><PriceUnit>1</PriceUnit><QuantityUnit>ST</QuantityUnit><QuantityAvailable>1</QuantityAvailable><QuantityProfile>1</QuantityProfile><Currency>EUR</Currency><Services /><Schedules>Geplante Liefertermine:  1 ST in KW 36.2017;</Schedules><Remark /><DangerMaterial /></Item></Items></SalesOrderSimulateConfirmation></Payload></Response></soap:Body></soap:Envelope> 

Nevertheless, the call to $soapclient->simulateOrder() returns null.

How do I get the PHP SoapClient to return an object instead of null?

Note: The xml I use for the soap call is generated manually by an override to SoapClient::__doRequest(). The code for the soap call looks like:

$soapClient = new SoapClient('https://webservices-test.ede.de:9443/ibis/ws/WS_EXT_ELC?wsdl', array(     'cache_wsdl'   => WSDL_CACHE_NONE,     'trace'        => true,     'exceptions'   => true,     'soap_version' => SOAP_1_2,     'features'     => SOAP_SINGLE_ELEMENT_ARRAYS,     'login' => '------', // cannot post here for security purposes     'password' => '-----', // cannot post here for security purposes     'stream_context' => (         stream_context_create(array(             'ssl' => array(                 'verify_peer' => false,                 'verify_peer_name' => false,                 'allow_self_signed' => true               )          )) )); $result = $soapClient->simulateOrder(); 

No exceptions are thrown, but $result is null

3 Answers

Answers 1

The problem is the SSL setup, the error that is thrown when I try to call your code on my server is as follows:

Fatal error: Uncaught SoapFault exception: [WSDL] SOAP-ERROR: Parsing WSDL: Couldn't load from 'https://webservices-test.ede.de:9443/ibis/ws/WS_EXT_ELC?wsdl' : failed to load external entity "https://webservices-test.ede.de:9443/ibis/ws/WS_EXT_ELC?wsdl" in /home/repojarilo/public_html/sc.php:22 Stack trace: #0 /home/repojarilo/public_html/sc.php(22): SoapClient->SoapClient('https://webserv...', Array) #1 {main} thrown in ... on line 22

I am assuming you are trying to get the code to work with a self signed certificate as indicated in your SSL array inside of the request, however it looks like the SoapClient is not paying attention to it and throwing an error anyway.

So my solution would be to either buy an SSL (very cheap now days, try sites such as namecheap etc...) or use something like https://letsencrypt.org/ to obtain an SSL that will allow your soap client to work correctly.

Lastly I noticed a typo, in your code one line before last you have )); which should read )));.

Koda

Answers 2

The Problem is that SOAP needs a valid SSL-Certificate.

For an testing-server it's sometimes not worth the effort, so maybe this link help you to use a little workarround, to got your SOAP-Request working without need to create a fully-validated SSL-Certificat:

http://automationrhapsody.com/send-soap-request-over-https-without-valid-certificates/

Answers 3

Problem is not your certificate as client, but server certificate itself (try to load https://webservices-test.ede.de:9443/ibis/ws/WS_EXT_ELC?wsdl in a browser), that is invalid. You can ignore it perfectly, as server certificate it's mainly to avoid phishing, and I understand that url it's really the one you're attempting to reach. In command line curl, this is realized with the -k option. In php, SoapClient exactly, you can use this (exactly your problem, check third answer, and see what says about PHP7)

NOTE: You are loading wsdl, the definition file of the service, at each construction of SoapClient. If you store $soapclient as a static variable, you can use it's methods all the time without the need of recreate the client object (and so, avoiding to reload and reinterpret the wsdl file, that can delay perfectly from 1 to 5 seconds) all the time.

Read More

Friday, July 7, 2017

Retrieve data from web service with ws addressing

Leave a Comment

I have a web service on a client site from which I need to report.

Locally, I mimicked the service using the provided wsdls and have been able to report on these. However, now pointing at the client site I am unable to access the data as the service requires ws addressing headers to be included.

The webservice is expecting the below:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:add="http://www.w3.org/2005/08/addressing" xmlns:ns="CustomerNamespace" xmlns:sch="Schema.xsd">    <soapenv:Header>       <add:From>          <add:Address>Something</add:Address>          <add:ReferenceParameters>             <ns:TransactionGroupID>SomeOtherThing</ns:TransactionGroupID>             <ns:SenderID>911</ns:SenderID>          </add:ReferenceParameters>       </add:From>       <add:Action>Request</add:Action>       <add:MessageID>TestGUID</add:MessageID>    </soapenv:Header>    <soapenv:Body>       <sch:Request>          <sch:SearchCustomerSystem>SystemXYZ</sch:SearchCustomerSystem>           <sch:ServiceID>999999999999</sch:ServiceID>       </sch:Request>    </soapenv:Body> </soapenv:Envelope> 

At present, I ccan get SSRS to produce the below:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">   <soap:Body>     <Request xmlns="Schema.xsd">       <ServiceID>           999999999999         </ServiceID>     </Request>   </soap:Body> </soap:Envelope> 

Other than creating a custom data extension (which I would rather avoid), is there a way of getting the ws addressing headers into the request?

2 Answers

Answers 1

The following snippet is the part of our WSDL that may be helpful if you have ability to change your WSDL. You will likely only need a bit of the namespaces, particularly the "addressing" related items. The "wsaw" namespace is the one used on our Action attributes that live on wsdl:input attributes under path of wsdl:portType -> wsdl:operation.

  <wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="OurTargetNamespaceHere" xmlns:wsa10="http://www.w3.org/2005/08/addressing" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" name="OurServiceNameHere" targetNamespace="OurTargetNamespaceHere">   <wsp:Policy wsu:Id="OurCustomPolicy_policy">     <wsp:ExactlyOne>       <wsp:All>         <sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">           <wsp:Policy>             <sp:TransportToken>               <wsp:Policy>                 <sp:HttpsToken RequireClientCertificate="false"/>               </wsp:Policy>             </sp:TransportToken>             <sp:AlgorithmSuite>               <wsp:Policy>                 <sp:Basic256/>               </wsp:Policy>             </sp:AlgorithmSuite>             <sp:Layout>               <wsp:Policy>                 <sp:Strict/>               </wsp:Policy>             </sp:Layout>           </wsp:Policy>         </sp:TransportBinding>       </wsp:All>     </wsp:ExactlyOne>   </wsp:Policy> 

Answers 2

For this example I will be using C#

Using the expected envelope in your example the following classes were derived.

/// <remarks/> [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.xmlsoap.org/soap/envelope/")] [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://schemas.xmlsoap.org/soap/envelope/", IsNullable = false)] public partial class Envelope {     /// <remarks/>     public EnvelopeHeader Header { get; set; }     /// <remarks/>     public EnvelopeBody Body { get; set; } }  /// <remarks/> [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.xmlsoap.org/soap/envelope/")] public partial class EnvelopeHeader {     /// <remarks/>     [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://www.w3.org/2005/08/addressing")]     public From From { get; set; }     /// <remarks/>     [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://www.w3.org/2005/08/addressing")]     public string Action { get; set; }     /// <remarks/>     [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://www.w3.org/2005/08/addressing")]     public string MessageID { get; set; } }  /// <remarks/> [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.w3.org/2005/08/addressing")] [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.w3.org/2005/08/addressing", IsNullable = false)] public partial class From {     /// <remarks/>     public string Address { get; set; }     /// <remarks/>     public FromReferenceParameters ReferenceParameters { get; set; } }  /// <remarks/> [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.w3.org/2005/08/addressing")] public partial class FromReferenceParameters {     /// <remarks/>     [System.Xml.Serialization.XmlElementAttribute(Namespace = "CustomerNamespace")]     public string TransactionGroupID { get; set; }     /// <remarks/>     [System.Xml.Serialization.XmlElementAttribute(Namespace = "CustomerNamespace")]     public ushort SenderID { get; set; } }  /// <remarks/> [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.xmlsoap.org/soap/envelope/")] public partial class EnvelopeBody {     /// <remarks/>     [System.Xml.Serialization.XmlElementAttribute(Namespace = "Schema.xsd")]     public Request Request { get; set; } }  /// <remarks/> [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "Schema.xsd")] [System.Xml.Serialization.XmlRootAttribute(Namespace = "Schema.xsd", IsNullable = false)] public partial class Request {     /// <remarks/>     public string SearchCustomerSystem { get; set; }     /// <remarks/>     public ulong ServiceID { get; set; } } 

Using the above classes, the following Unit Test will be used to demonstrate

a way of getting the ws addressing headers into the request

[TestClass] public class MyTestClass {     [TestMethod]     public void _ws_addressing_headers_into_the_request() {          var xmlWithBodyOnly = GetEnvelopFromSSRS();         var header = BuildHeader();         var result = AppendHeader(xmlWithBodyOnly, header);      }      private static EnvelopeHeader BuildHeader() {         var header = new EnvelopeHeader {             From = new From {                 Address = "Someting",                 ReferenceParameters = new FromReferenceParameters {                     SenderID = 911,                     TransactionGroupID = "SomeOtherThing"                 }             },             Action = "Request",             MessageID = "SomeGuid"         };         return header;     }      private static string GetEnvelopFromSSRS() {         var xmlWithBodyOnly = @" <soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>   <soap:Body>     <Request xmlns='Schema.xsd'>       <ServiceID>           999999999999         </ServiceID>     </Request>   </soap:Body> </soap:Envelope>";         return xmlWithBodyOnly;     }      private string AppendHeader(string xml, EnvelopeHeader header) {         var result = string.Empty;         // convert string to stream         var data = Encoding.UTF8.GetBytes(xml);         using (var inStream = new MemoryStream(data)) {             // Create an instance of the XmlSerializer specifying type and namespace.             var serializer = new XmlSerializer(typeof(Envelope));             //Deseiralize XML to something we can work with             var envelope = (Envelope)serializer.Deserialize(inStream);             if (envelope != null) {                 //Append the header                 envelope.Header = header;                 //Serialize the envelope back to XML                 using (var outStream = new MemoryStream()) {                     serializer.Serialize(outStream, envelope);                     result = Encoding.UTF8.GetString(outStream.ToArray());                 }             }         }         return result;     } } 

Explanation.

 var xmlWithBodyOnly = GetEnvelopFromSSRS(); 

mimics getting what you have been able to produce via SSRS based on the example provided in your original question.

 var header = BuildHeader(); 

Using the derived classes you can easily create and populate the necessary properties for your header as you see fit

private static EnvelopeHeader BuildHeader() {     var header = new EnvelopeHeader {         From = new From {             Address = "Someting",             ReferenceParameters = new FromReferenceParameters {                 SenderID = 911,                 TransactionGroupID = "SomeOtherThing"             }         },         Action = "Request",         MessageID = "SomeGuid"     };     return header; } 

Now for the meat of the matter.

var result = AppendHeader(xmlWithBodyOnly, header); 

Once you have the envelope and the header you are now ready to append the ws addressing header to the request

private string AppendHeader(string xml, EnvelopeHeader header) {     var result = string.Empty;     // convert string to stream     var data = Encoding.UTF8.GetBytes(xml);     using (var inStream = new MemoryStream(data)) {         // Create an instance of the XmlSerializer specifying type and namespace.         var serializer = new XmlSerializer(typeof(Envelope));         //Deseiralize XML to something we can work with         var envelope = (Envelope)serializer.Deserialize(inStream);         if (envelope != null) {             //Append the header             envelope.Header = header;             //Serialize the envelope back to XML             using (var outStream = new MemoryStream()) {                 serializer.Serialize(outStream, envelope);                 result = Encoding.UTF8.GetString(outStream.ToArray());             }         }     }     return result; } 

The comments in the code explain what was done.

For the above example, given the following envelope

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">   <soap:Body>     <Request xmlns="Schema.xsd">       <ServiceID>           999999999999         </ServiceID>     </Request>   </soap:Body> </soap:Envelope> 

When used in the above code produces the following output.

<?xml version="1.0"?> <Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/soap/envelope/">   <Header>     <From xmlns="http://www.w3.org/2005/08/addressing">       <Address>Someting</Address>       <ReferenceParameters>         <TransactionGroupID xmlns="CustomerNamespace">SomeOtherThing</TransactionGroupID>         <SenderID xmlns="CustomerNamespace">911</SenderID>       </ReferenceParameters>     </From>     <Action xmlns="http://www.w3.org/2005/08/addressing">Request</Action>     <MessageID xmlns="http://www.w3.org/2005/08/addressing">SomeGuid</MessageID>   </Header>   <Body>     <Request xmlns="Schema.xsd">       <ServiceID>999999999999</ServiceID>     </Request>   </Body> </Envelope> 

This output can now be used to make your request to the web service as desired. The models can also be modified as needed based on what is required for the web service request.

Read More

Thursday, April 20, 2017

Why do I get this error “falseObject reference not set to an instance of an object.” when I call an operation in my webservice

Leave a Comment

I have a web service and I am calling one of its operations using SOAP client in PHP but all I get is this ["any"]=> string(120) "falseObject reference not set to an instance of an object.

I want to know is there anything wrong in my code because I belive that my connection to the web service is %100 working.

Is there anything wrong in the xml string that I am creating ?

The operation is :

<wsdl:operation name="XmlIslet">     <wsdl:input message="tns:XmlIsletSoapIn"/>     <wsdl:output message="tns:XmlIsletSoapOut"/> </wsdl:operation> 

and the description of its parameters in the WSDL is :

<wsdl:types>     <s:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/">         <s:element name="XmlIslet">             <s:complexType>                 <s:sequence>                     <s:element minOccurs="0" maxOccurs="1" name="xmlIslem">                         <s:complexType>                             <s:sequence>                                 <s:any/>                             </s:sequence>                         </s:complexType>                     </s:element>                     <s:element minOccurs="0" maxOccurs="1" name="xmlYetki">                         <s:complexType>                             <s:sequence>                                 <s:any/>                             </s:sequence>                         </s:complexType>                     </s:element>                 </s:sequence>             </s:complexType>         </s:element>         <s:element name="XmlIsletResponse">             <s:complexType>                 <s:sequence>                     <s:element minOccurs="0" maxOccurs="1" name="XmlIsletResult">                         <s:complexType mixed="true">                             <s:sequence>                                 <s:any/>                             </s:sequence>                         </s:complexType>                     </s:element>                 </s:sequence>             </s:complexType>         </s:element>     </s:schema> </wsdl:types> 

My soap and PHP code is the following :

<?php $username = "username"; $password = "password"; $xmlString = "<Firmalar></Firmalar>";  function strtoXmldocument($str) {     $dom = new DOMDocument();     $str1 = $str;     return $dom->loadXML($str1); }  function stringToDataset($xmlString, $username, $password)      {                            $client = new SoapClient('http://1.1.1.1/WSTEST/Service.asmx?WSDL');      $response = $client->XmlIslet(strtoXmldocument($xmlString)->documentElement,   strtoXmldocument("<Kullanici><Adi>" .$username. "</Adi><Sifre>" .$password. "</Sifre></Kullanici>")->documentElement);  var_dump($response); }  stringToDataset($xmlString, $username, $password); ?> 

The SOAP request is as the following:

POST /WSTEST/Service.asmx HTTP/1.1 Host: 1.1.1.1 Content-Type: application/soap+xml; charset=utf-8 Content-Length: length  <?xml version="1.0" encoding="utf-8"?> <soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">   <soap12:Body>     <XmlIslet xmlns="http://tempuri.org/">       <xmlIslem>xml</xmlIslem>       <xmlYetki>xml</xmlYetki>     </XmlIslet>   </soap12:Body> </soap12:Envelope> 

The SOAP response :

HTTP/1.1 200 OK Content-Type: application/soap+xml; charset=utf-8 Content-Length: length  <?xml version="1.0" encoding="utf-8"?> <soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">   <soap12:Body>     <XmlIsletResponse xmlns="http://tempuri.org/">       <XmlIsletResult>xml</XmlIsletResult>     </XmlIsletResponse>   </soap12:Body> </soap12:Envelope> 

vardump output is :

usernamepasswordobject(stdClass)#2 (1) { ["XmlIsletResult"]=> object(stdClass)#3 (1) { ["any"]=> string(120) "falseObject reference not set to an instance of an object." } }  

EDIT : I tried to get the request xml using htmlentities($client->__getLastRequest()) which shows me an empty body of my request :

========= REQUEST ==========  string(292)  "<?xml version="1.0" encoding="UTF-8"?>  <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://tempuri.org/"> <SOAP-ENV:Body> <ns1:XmlIslet> <ns1:xmlIslem/> <ns1:xmlYetki/> </ns1:XmlIslet> </SOAP-ENV:Body> </SOAP-ENV:Envelope> " 

1 Answers

Answers 1

You're most likely communicating with a .NET service. This error message is basically a "variable undefined" message.

The WSDL file says, you request must contain two entities: xmlIslem and xmlYetki. But their internal structure is not properly defined, it can be "any"-thing. This, however, doesn't mean, that the remove web service doesn't expect you to provide some data. It looks like you need to pass some data, which you don't, hence the error.

I would contact the web service provider and requested the documentation or specific request examples.

Read More

Tuesday, March 7, 2017

SoapHttpClientProtocol and TLS 1.2 - The client and server cannot communicate, because they do not possess a common algorithm

Leave a Comment

There are numerous posts on SO about this and I have scoured them, but still don't have a solution. I am hoping that someone can point me in the right direction.

We have a requirement now to use TLS 1.2 to connect to a remote provider. So I have installed Windows Server 2016 and configured it as needed:

enter image description here enter image description here

I know the remote server is running TLS 1.2 and that it supports the highlighted cipher.

We connect to the remote end point using C# proxy class generated by the WSDL provided by the provider - before they converted their end to TLS (System.Web.Services.Protocols.SoapHttpClientProtocol).

When I connect using the proxy I get an exception with the inner exception being "The client and server cannot communicate, because they do not possess a common algorithm".

I cannot see anywhere that ServicePointManager.SecurityProtocol so I am assuming .NET is picking up TLS 1.2 as it is the only enabled protocol? No idea how it is doing the cipher.

Can someone tell me how I go about attempting to fix this? If possible I don't want to regenerate the WSDL proxy class.

1 Answers

Answers 1

If your client application was compiled against .NET Framework 4.5.2 or lower, then by default ServicePointManager.SecurityProtocol is initialized to SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls (SSL 3.0 and TLS 1.0 only), so it won't be able to connect to a remote server that requires TLS 1.2.

There are several ways to allow your client application to use TLS 1.2:

  • Recompile your client application against .NET Framework 4.6 or later. (In Visual Studio, open your project's property pages, go to the Application tab, and change the Target Framework.)
  • On the client machine, run RegEdit.exe, go to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ .NETFramework\v4.0.30319, add a DWORD (32-bit) value named SchUseStrongCrypto, and set it to 1. (This flag causes ServicePointManager.SecurityProtocol to be initialized to Tls | Tls11 | Tls12.)
  • When your client application starts up, turn on TLS 1.2: ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;

There's no need to regenerate your proxy class because it's not responsible for negotiating the TLS protocol or cipher.

Read More

Wednesday, March 1, 2017

Post as Option, Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header

Leave a Comment

XMLHttpRequest cannot load http://xxx.xxx. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 500.

I am trying to send a xml soap with ajax but gives me that error. I have tried many option but nothing seems to work, here is the code:

var soapMessage =                 '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://xxx.xxx/">'+                 '<soapenv:Header/>'+                 '<soapenv:Body>'+                    '<wsdl:test1>'+                       '<PUI>12345</PUI>'+                    '</wsdl:test1>'+                ' </soapenv:Body>'+              '</soapenv:Envelope>';              $.ajax({                 url: 'http://xxx.xxx',                  type: 'POST',                 dataType: 'xml',                  data: soapMessage,                  crossDomain: true,                 processData: false,                 contentType: 'text/xml; charset=\"utf-8\"',                 headers: {                     SOAPAction: "http://xxx.xxx"                 },                 success: function (msg, data) {                     alert(msg);                  },                 error: function (msg, data) {                     alert("Error");                 }             }); 

what am I doing wrong here? I send a POST action but it read it as OPTION. How to fix this?

I use Boomerang Rest and Soap Client to test this service and it gives me response correctly. When I use my own program as above it gives me XMLHttpRequest cannot load http://xxxxx" error. I am using apache tomcat 6.0 and using a Java web Application for the code

2 Answers

Answers 1

You’re doing that request cross-origin, so the server you’re making the request to must send an Access-Control-Allow-Origin response header to indicate it allows cross-origin requests.

See https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS for more details.

For security reasons, browsers restrict cross-origin HTTP requests initiated from within scripts. For example, XMLHttpRequest and Fetch follow the same-origin policy. So, a web application using XMLHttpRequest or Fetch could only make HTTP requests to its own domain.

And the reason an OPTIONS request happens is that when you send a cross-origin request with a Content-Type header that has a value other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, your browser first does a CORS preflight check.

Your request sends Content-Type: text/xml; charset="utf-8", so that causes a preflight.

As far as workarounds if the server you’re sending the request to is not one that you control and can configure, you can use an open reverse proxy like https://cors-anywhere.herokuapp.com/.

The way it works is that instead of sending your request directly to http://xxx.xxx, you send it instead to https://cors-anywhere.herokuapp.com/http://xxx.xxx and that proxies your request and responds to the browser with Access-Control-Allow-Origin and other expected CORS headers.

Of course you need to understand that if your request contains any confidential information, you’d be exposing it to the maintainers of cors-anywhere.herokuapp.com if they log data for requests.

Answers 2

My work around for this was to write a filter that appends the origin as an accepted origin onto any options request and added it to whatever servlet that would need to accept such requests. Here's my implementation:

public class CorsFilter implements Filter {      private static List<String> validServers = Arrays.asList([you need to fill this in with whatever sites you want to allow access]);      @Override     public void init(FilterConfig filterConfig) throws ServletException {     }      @Override     public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {         if (servletRequest instanceof HttpServletRequest) {             HttpServletRequest request = (HttpServletRequest) servletRequest;             HttpServletResponse response = (HttpServletResponse) servletResponse;             String origin = request.getHeader("Origin");             if (StringUtils.isNotBlank(origin)) { //this is a cors request                 boolean hasPrefix = origin.contains("/");                 boolean hasPort = origin.contains(":");                 String serverAlias = origin.substring(hasPrefix ? origin.lastIndexOf("/") + 1 : 0, hasPort ? origin.lastIndexOf(":") : origin.length());                 if (validServers.contains(serverAlias)) {                     response.setHeader("Access-Control-Allow-Credentials", "true");                     response.setHeader("Access-Control-Allow-Methods", "OPTIONS, POST, GET, PUT, DELETE");                     response.setHeader("Access-Control-Allow-Origin", origin);                     response.setHeader("Access-Control-Allow-Headers", "Content-Type");                     //credentials are not sent on options requests, kick out here so that the access control headers and nothing else can be returned                     if ("OPTIONS".equals(request.getMethod())) {                         response.setStatus(200);                         return;                     }                 } else {                     response.sendError(HttpStatus.SC_FORBIDDEN);                     response.flushBuffer();                     return;                 }             }         }          filterChain.doFilter(servletRequest, servletResponse);     }       @Override     public void destroy() {     } } 
Read More

Friday, January 20, 2017

How does it work with the magic WSDL URI query parameter?

Leave a Comment

I'm building a Soap server within a Symfony application. As first step I created a controller with my "hello world" Soap action and defined the route for it:

routing.yml

api.soap.foo     path: /soapapi/foo     defaults: { _controller: SoapBundle\Controller\FooController:bar }     methods: [GET, HEAD, POST] 

FooController#bar(...)

protected function bar(Request $request) {     $autodiscover = new AutoDiscover();     $autodiscover         ->setClass(MyFooBarService::class)         ->setUri('http://my-app.loc/soapapi/foo/bar')         ->setServiceName('MyFooBarService')     ;     $wsdl = $autodiscover->generate();     $wsdl->dump(__DIR__ . '/soapapi-foo-bar.wsdl');     $server = new SoapServer(__DIR__ . '/soapapi-foo-bar.wsdl');     $server->setObject($this->myFooBarService);     $response = new Response();     $response->headers->set('Content-Type', 'text/xml; charset=ISO-8859-1');     ob_start();     $server->handle();     $response->setContent(ob_get_clean());     return $response; } 

Now, when I call http://my-app.loc/soapapi/foo/bar in a browser or using cURL (so via HTTP GET), I get an error:

<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">     <SOAP-ENV:Body>         <SOAP-ENV:Fault>             <faultcode>SOAP-ENV:Client</faultcode>             <faultstring>Bad Request</faultstring>         </SOAP-ENV:Fault>     </SOAP-ENV:Body> </SOAP-ENV:Envelope> 

But when I call http://my-app.loc/soapapi/foo/bar?wsdl, I actually get the (generated) WSDL document. Why? I have not defined anywhere, that it should work like this. Why and how does this (magic) work? Is it Symfony specific magic?

1 Answers

Answers 1

This is a great question.

No this is not Symfony specific, it's a behavior of the built-in SOAP server in PHP. When the endpoint URL is accessed with ?wsdl appended, the SOAP server will respond with the wsdl document that it was instantiated with in the constructor:

$server = new SoapServer(__DIR__ . '/soapapi-foo-bar.wsdl'); 

I've not been able to find where this behavior is documented on the PHP website, but it clearly exists and is reproducible.

The code for the feature can be found in PHP's source code starting on line 1550 and ending on line 1592. The code checks if the request method is GET and checks for the presence of a 'wsdl' query parameter.

Read More

Wednesday, March 30, 2016

WCF maxes CPU when waiting on _TransparantProxyStub_CrossContext function during call

Leave a Comment

I'm getting heavy CPU usage when making calls to Cisco's AXL SOAP API using WCF. I start by creating a service model clientbase using generated classes from wsdl. I'm using basichttpbinding and transfermode as buffered. When executing a call, the CPU maxes out, and a CPU profile shows that 96% of CPU time is at _TransparentProxyStub_CrossContext@0 from clr.dll that is called after calls such as base.Channel.getPhone(request);. More correctly, the call maxes out the CPU core that the process is running on.

Here's a snip of the client creation from the wsdl generate

[System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] public partial class AXLPortClient : System.ServiceModel.ClientBase<AxlNetClient.AXLPort>, AxlNetClient.AXLPort {      public AXLPortClient()     {     }      public AXLPortClient(string endpointConfigurationName) :              base(endpointConfigurationName)     {     }      ... 

This is how I create the client:

public class AxlClientFactory : IAxlClientFactory {     private const string AxlEndpointUrlFormat = "https://{0}:8443/axl/";      public AXLPortClient CreateClient(IUcClientSettings settings)     {         ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;         ServicePointManager.Expect100Continue = false;                                var basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);         basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;          basicHttpBinding.MaxReceivedMessageSize = 20000000;         basicHttpBinding.MaxBufferSize = 20000000;         basicHttpBinding.MaxBufferPoolSize = 20000000;          basicHttpBinding.ReaderQuotas.MaxDepth = 32;         basicHttpBinding.ReaderQuotas.MaxArrayLength = 20000000;         basicHttpBinding.ReaderQuotas.MaxStringContentLength = 20000000;          basicHttpBinding.TransferMode = TransferMode.Buffered;         //basicHttpBinding.UseDefaultWebProxy = false;          var axlEndpointUrl = string.Format(AxlEndpointUrlFormat, settings.Server);         var endpointAddress = new EndpointAddress(axlEndpointUrl);         var axlClient = new AXLPortClient(basicHttpBinding, endpointAddress);         axlClient.ClientCredentials.UserName.UserName = settings.User;         axlClient.ClientCredentials.UserName.Password = settings.Password;         return axlClient;     } } 

The generated wsdl code for the AXL API is very large. Both initial and subsequent calls have the CPU issue, although subsequent calls are faster. Is there anything else I can do to debug this issue? Is there a way to reduce this high CPU usage?

Update

A bit more info with the bounty:

I've created the C# classes like so:

svcutil AXLAPI.wsdl AXLEnums.xsd AXLSoap.xsd /t:code /l:C# /o:Client.cs /n:*,AxlNetClient 

You have to download the wsdl for Cisco's AXL api from a call manager system. I'm using the 10.5 version of the API. I believe the a major slowdown is related to XML processing. The WSDL for the api is huge with the resulting classes making a 538406 lines of code!

Update 2

I've turned on WCF tracing with all levels. The largest time difference is in the process action activity between "A message was written" and "Sent a message over a channel" in which nearly a full minute passes between these two actions. Other activities (construct channel, open clientbase and close clientbase) all execute relatively fast.

Update 3

I've made two changes to the generated client classes. First, I removed the ServiceKnownTypeAttribute from all the operation contracts. Second, I removed the XmlIncludeAtribute from some of the serializable classes. These two changes reduced the file size of the generated client by more than 50% and had a small impact on test times (a reduction of about 10s on a 70s test result).

I also noticed that I have roughly 900 operation contracts for a single service interface and endpoint. This is due to the wsdl for the AXL API grouping all operations under a single namespace. I'm thinking about breaking this up, but that would mean creating multiple clientbases that would each implement a reduced interface and end up breaking everything that implements this wcf library.

Update 4

It looks like the number of operations is the central problem. I was able to separate out operations and interface definitions by verb (e.g. gets, adds, etc) into their own clientbase and interface (a very slow process using sublime text and regex as resharper and codemaid couldn't handle the large file that's still 250K+ lines). A test of the "Get" client with about 150 operations defined resulted in a 10 second execution for getPhone compared to a previous 60 second result. This is still a lot slower than it should be as simply crafting this operation in fiddler results in a 2 second execution. The solution will probably be reducing the operation count even more by trying to separate operations further. However, this adds a new problem of breaking all systems that used this library as a single client.

0 Answers

Read More

Tuesday, March 22, 2016

Axis: createCall with params

Leave a Comment

I generated java code with wsdl2java based on Magento WSDL (http://host/api?wsdl), but cannot call any procedure with params

Environment:

  • JDK 1.8
  • AXIS 1.4
  • php 5.6
  • Magento 1.6

Problem:

For example, product.info api method required 2 params: sessionId and productId

code:

MagentoService magentoService = new MagentoServiceLocator(); Mage_Api_Model_Server_HandlerBindingStub service = new Mage_Api_Model_Server_HandlerBindingStub(new URL("http://myhost/api"), magentoService);  String sessionId = service.login("api-user", "AAAAAAAAAAAAAAAA");  Call serviceCall = service.createCall(); serviceCall.setOperationName(new QName("call")); serviceCall.setTargetEndpointAddress(new URL("http://myhost/api")); serviceCall.addParameter("sessionId", Constants.XSD_STRING, ParameterMode.IN); serviceCall.addParameter("resourcePath", Constants.XSD_STRING, ParameterMode.IN); serviceCall.addParameter("productId", Constants.XSD_STRING, ParameterMode.IN); serviceCall.setReturnType(Constants.SOAP_MAP); serviceCall.invoke("call", new Object[] {sessionId, "product.info", new Object[]{2115}});     

i checked database, product really exists. no matter which id used, i getting error:

AxisFault  faultCode: 101  faultString: Product not exists. 

i try another api methods, like a customer.info and have the same result.

how to pass parameters correctly?

What i did:

1 Answers

Answers 1

The Magento documentation is faulty: http://www.magentocommerce.com/api/soap/catalog/catalogProduct/catalog_product.info.html

The parameter "productId" is in reality called "product".

Read More

Webservice change method response without notifying clients

Leave a Comment

Let's assume I have a webservice which returns a class on all methods, informing the client the status of the process, for example:

public class WsResult {    string result; // either "error" or "ok"  } 

Now we'd like to add a property to this class, without forcing all clients consuming our service to update their software. Is this possible?

For example:

public class WsResult {    public string result; // either "error" or "ok"    public Guid? someIdentifier;  } 

I'm looking for answers on both WCF and ASMX.

2 Answers

Answers 1

WCF

It is possible. You can simply add a new property and it'll work providing that this new property is not required. For more details see point 8 of Best Practices: Data Contract Versioning article.

If you need to handle round-tripping scenario you should read about IExtensibleDataObject interface. Round-tripping occurs when data is sent from a server to a client and it is expected that it'll be sent back. See Forward-Compatible Data Contracts article for details.

ASMX

With ASMX a situation is the same. You can add a new property and all clients should work. In this case you can also use IExtensibleDataObject interface.

Final Comments

This answer is based on empirical tests with VS 2015. I strongly suggest you to do the same i.e.: write simple WCF/ASMX servers and clients and verify behaviour described by me. It took me just several minutes to do so. Or even better you can use already existing services.

I recommend additional tests because you may be using some non-default configuration which changes the default behaviour of WCF/ASMX services so it is better to check. I'm not aware of this kind of configuration but you never know.

Answers 2

With WCF you can actually have different classes on the client and server side, which is what will normally happen as well when using the Add service reference UI. The trick to make this work is to set the namespace and the name on the DataContract attribute (and perhaps even the name on the DataMember attribute if the member names differ).

Only the properties that match will be deserialized, as such adding a property on the server side won't impact the client side.

Read More

Sunday, March 20, 2016

Generating Request/Response XML from a WSDL

Leave a Comment

Is there a way to generate Request & Response XML formats from just a WSDL file - if the webservice is not live right now.

SoapUI doesn't give me the response unless it contacts the Webservice with a request. Is there any other tool which can do this?

I should assume this information is available - because without it - client stub frameworks like Axis/JAXWS etc won't be able to generate stubs for generating the requesting and then interpreting the response.

3 Answers

Answers 1

Since you are saying the webservice is not live right now, you can do it by creating mockservices which will create the sample response format.

Answers 2

This can be done using soapUI. (I'm using 5.2.1) The title of the question says "Request & Response XML" while the question body says "Request & Response XML formats" which I interpret as the schema of the request and response. At any rate, the following will give you the schema which you can use on XSD2XML to generate sample XML.

  1. Start a "New Soap Project", enter a project name and WSDL location; choose to "Create Requests", unselect the other options and click OK.
  2. Under the "Project" tree on the left side, right-click an interface and choose "Show Interface Viewer".
  3. Select the "WSDL Content" tab.
  4. You should see the WSDL text on the right hand side; look for the block starting with "wsdl:types" below which are the schema for the input and output messages.
  5. Each schema definition starts with something like <s:element name="GetWeather"> and ends with </s:element>.
  6. Copy out the block into a text editor; above this block add: <?xml version="1.0" encoding="UTF-8"?> <s:schema xmlns:s="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
  7. Below the block of copied XML, add </s:schema>
  8. Decide if you need "UTF-16" instead of "UTF-8"
  9. The "s:" and the "xmlns:s" should match the block you copied (step 5)
  10. Save this file with ".xsd" extension; if you have "XML Copy Editor" or some such tool (XML Spy, may be) you should check that this is well-formed XML and valid schema.
  11. Repeat for all "element" items in the right hand pane of soapUI until you reach
  12. This way you'll get some type definitions you might not be interested in. If you want to pick and choose, use the following method: Look through the "wsdl:operation" items under "wsdl:portType" in the WSDL text below the type definitions. They will have "wsdl:input" and "wsdl:output". Take the message names from "wsdl:input" and "wsdl:output". Match them against "wsdl:message" names which will likely be above the "wsdl:portType" entries in the WSDL. Get the "wsdl:part" element name from "wsdl:message" item and look for that name as element name under "wsdl:types". Those will be the schema of interest to you.

If you actually have the complete WSDL as a file available to you, you don't even need soapUI.

You can try above procedure out using the WSDL at http://www.webservicex.com/globalweather.asmx?wsdl

Answers 3

Try this online tool: https://www.wsdl-analyzer.com It appears to be free and does a lot more than generate the XML for requests and response. There is also this: https://www.oxygenxml.com/xml_editor/wsdl_soap_analyzer.html, which can be downloaded, but not free.

Read More