Вы находитесь на странице: 1из 6

How to invoke a C# web service through PHP?

I've written a web service using ASP.NET (in C#) and I'm attempting to write an example PHP client using NuSOAP. Where I'm tripped up on are examples of how to do this; some show soapval being used (and I don't quite understand the parameters - for example passing false as string types, etc.), while others are just using straight arrays. Let's say the WSDL for my web service as reported by http://localhost:3333/Service.asmx?wsdl looks something like:
POST /Service.asmx HTTP/1.1 Host: localhost Content-Type: text/xml; charset=utf-8 Content-Length: length SOAPAction: "http://tempuri.org/webservices/DoSomething" <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <DoSomething xmlns="http://tempuri.org/webservices"> <anId>int</anId> <action>string</action> <parameters> <Param> <Value>string</Value> <Name>string</Name> </Param> <Param> <Value>string</Value> <Name>string</Name> </Param> </parameters> </DoSomething> </soap:Body> </soap:Envelope>

My first PHP attempt looks like:


<?php require_once('lib/nusoap.php'); $client = new nusoap_client('http://localhost:3333/Service.asmx?wsdl'); $params = array( 'anId' => 3, //new soapval('anId', 'int', 3), 'action' => 'OMNOMNOMNOM', 'parameters' => array( 'firstName' => 'Scott', 'lastName' => 'Smith' ) ); $result = $client->call('DoSomething', $params,

'http://tempuri.org/webservices/DoSomething', 'http://tempuri.org/webservices/DoSomething'); print_r($result); ?>

Now aside from the Param type being a complex type which I'm pretty sure my simple $array attempt will not automagically work with, I'm breakpointing in my web service and seeing the method I've marked as WebMethod (without renaming it, its literally DoSomething) and seeing the arguments are all default values (the int is 0, the string is null, etc.). What should my PHP syntax look like, and what do I have to do to pass the Param type correctly?

Answers 1. You have to wrap things in tons of nested arrays.


<?php require_once('lib/nusoap.php'); $client = new nusoap_client('http://localhost:3333/Service.asmx?wsdl'); $params = array( 'anId' => 3, 'action' => 'OMNOMNOMNOM', 'parameters' => array( 'Param' => array( array('Name' => 'firstName', 'Value' => 'Scott'), array('Name' => 'lastName' 'Value' => 'Smith') ) ); $result = $client->call('DoSomething', array($params), 'http://tempuri.org/webservices/DoSomething', 'http://tempuri.org/webservices/DoSomething'); print_r($result); ?>

2.

Sort of unrelated but since PHP5 you have native support for SOAP.

$client = new SoapClient("some.wsdl"); $client->DoSomething($params);

That might be a little more convenient. http://se.php.net/soap

3. Here the sample with native SOAP support:

// Create a new soap client based on the service's metadata (WSDL) $client = new SoapClient("http://some.wsdl", array('location' => 'http://127.0.0.100:80/IntegrationService/php')); $params = array(); $params['lead']['Firstname'] $params['lead']['Lastname'] $params['lead']['Product'] $params['lead']['JobTitle'] $params['lead']['Email'] $params['lead']['Phone'] $params['lead']['CompanyName'] $params['lead']['City'] $params['lead']['Industry'] $client->SubmitLead($params); = = = = = = = = = $user->firstname; $user->lastname; $product; $user->job_title; $user->mail; $user->phone; $user->company_name; $user->city; $user->industry;

Where '.../IntegrationService/php' in SoapClient description is endpoint in WCF:

Here is an example of a php client talking to a asmx server: <?php $soapClient = new SoapClient("https://soapserver.example.com/blahblah.asmx?wsdl"); // Prepare SoapHeader parameters $sh_param = array( 'Username' => 'username', 'Password' => 'password'); $headers = new SoapHeader('http://soapserver.example.com/webservices', 'UserCredentials', $sh_param); // Prepare Soap Client $soapClient->__setSoapHeaders(array($headers)); // Setup the RemoteFunction parameters $ap_param = array( 'amount' => $irow['total_price']); // Call RemoteFunction () $error = 0; try { $info = $soapClient->__call("RemoteFunction", array($ap_param)); } catch (SoapFault $fault) { $error = 1; print(" alert('Sorry, blah returned the following ERROR: ".$fault->faultcode."-".$fault>faultstring.". We will now take you back to our home page.');

window.location = 'main.php'; ");


} if ($error == 0) { $auth_num = $info->RemoteFunctionResult; if ($auth_num < 0) { .... // Setup the OtherRemoteFunction() parameters $at_param = array( 'amount' => $irow['total_price'], 'description' => $description); // Call OtherRemoteFunction() $trans = $soapClient->__call("OtherRemoteFunction", array($at_param)); $trans_result = $trans->OtherRemoteFunctionResult; .... } else { // Record the transaction error in the database // Kill the link to Soap unset($soapClient); } } } } ?>

If you've been trying to send null to a service that considers empty property tags as empty strings rather than null, here's an extending class that fixes this using xsi:nil: <?php class XSoapClient extends SoapClient { const XSI_NS = "http://www.w3.org/2001/XMLSchema-instance"; const _NULL_ = "xxx_replacedduetobrokephpsoapclient_xxx"; protected $mustParseNulls = false; public function __doRequest($request, $location, $action, $version, $one_way = null) { if($this->mustParseNulls) { $this->mustParseNulls = false; $request = preg_replace('/<ns1:(\w+)>'.self::_NULL_.'<\/ns1:\\1>/', '<ns1:$1 xsi:nil="true"/>',

$request, -1, &$count); if ($count > 0) { $request = preg_replace('/(<SOAP-ENV:Envelope )/', '\\1 xmlns:xsi="'.self::XSI_NS.'" ', $request); } } return parent::__doRequest($request, $location, $action, $version, $one_way); } public function __call($method, $params) { foreach($params as $k => $v) { if($v === null) { $this->mustParseNulls = true; $params[$k] = self::_NULL_; } } return parent::__call($method, $params); } } ?>

PROBLEM (with SOAP extension under PHP5) of transferring object, which contains objects or array of objects. Nested object would not transfer. SOLUTION: This class was developed by trial and error by me. So these 23 lines of code for most developers writing under PHP5 solve fate of using SOAP extension. <?php /* According to specific of organization process of SOAP class in PHP5, we must wrap up complex objects in SoapVar class. Otherwise objects would not be encoded properly and could not be loaded on remote SOAP handler. Function "getAsSoap" call for encoding object for transmission. After encoding it can be properly transmitted. */ abstract class SOAPable { public function getAsSOAP() { foreach($this as $key=>&$value) { $this->prepareSOAPrecursive($this->$key);

} return $this; }

private function prepareSOAPrecursive(&$element) { if(is_array($element)) { foreach($element as $key=>&$val) { $this->prepareSOAPrecursive($val); } $element=new SoapVar($element,SOAP_ENC_ARRAY); }elseif(is_object($element)) { if($element instanceof SOAPable) { $element->getAsSOAP(); } $element=new SoapVar($element,SOAP_ENC_OBJECT); } } }
// -----------------------------------------// ABSTRACT EXAMPLE // ------------------------------------------

class PersonList extends SOAPable { protected $ArrayOfPerson; // variable MUST be protected or public! } class Person extends SOAPable {
//any data

}
$client=new SoapClient("test.wsdl", array( 'soap_version'=>SOAP_1_2, 'trace'=>1, 'classmap' => array('Person' => "Person", 'PersonList' => "PersonList") )); $PersonList=new PersonList; // some actions $PersonList->getAsSOAP(); $client->someMethod($PersonList); ?> So every class, which will transfer via SOAP, must be extends from class SOAPable. As you can see, in code above, function prepareSOAPrecursive search another nested objects in parent object or in arrays, and if does it, tries call function getAsSOAP() for preparation of nested objects, after that simply wrap up via SoapVar class. So in code before transmitting simply call $obj->getAsSOAP()

Вам также может понравиться