Генерация WSDL с помощью nusoap-return struct с различными типами (int, string, array of structs)
Я хотел бы запросить некоторые материалы через SOAP, генерируя WSDL с NuSOAP.
Я знаю, что есть много вопросов, связанных с этой темой, но мне не удалось адаптировать коды к моей конкретной проблеме.
мне удалось создать код WSDL, который возвращает только массив структур (ассоциативный массив), но Я хотел бы вернуть объект (struct), который содержит целочисленную переменную, строковую переменную и массив структуры.
и это код, который работает для возврата массива структур:
<?php
function getStuffs( $user='', $pass='' ) {
// here we can check user and pass and do whatever (if it isn't alright, we can throw exception or return NULL or sg. similar)
// .......
$stuff_array = array();
$stuff_array[] = array( 'id'=>122, 'name'=>'One stuff');
$stuff_array[] = array( 'id'=>213, 'name'=>'Another stuff');
$stuff_array[] = array( 'id'=>435, 'name'=>'Whatever stuff');
$stuff_array[] = array( 'id'=>65, 'name'=>'Cool Stuff');
$stuff_array[] = array( 'id'=>92, 'name'=>'Wow, what a stuff');
return $stuff_array;
}
require_once 'nusoap/lib/nusoap.php';
$server = new soap_server;
// $myNamespace = $_SERVER['SCRIPT_URI'];
$myNamespace = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'];
$server->configureWSDL('MyStuffService', 'urn:' . $myNamespace);
// $server->wsdl->schemaTargetNamespace = 'http://soapinterop.org/xsd/';
$server->wsdl->addComplexType(
// name
'Stuffs',
// typeClass (complexType|simpleType|attribute)
'complexType',
// phpType: currently supported are array and struct (php assoc array)
'struct',
// compositor (all|sequence|choice)
'all',
// restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
'',
// elements = array ( name = array(name=>'',type=>'') )
array(
'id' => array(
'name' => 'id',
'type' => 'xsd:int'
),
'name' => array(
'name' => 'name',
'type' => 'xsd:string'
)
)
);
$server->wsdl->addComplexType(
// name
'StuffsArray',
// typeClass (complexType|simpleType|attribute)
'complexType',
// phpType: currently supported are array and struct (php assoc array)
'array',
// compositor (all|sequence|choice)
'',
// restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
'SOAP-ENC:Array',
// elements = array ( name = array(name=>'',type=>'') )
array(),
// attrs
array(
array(
'ref' => 'SOAP-ENC:arrayType',
'wsdl:arrayType' => 'tns:Stuffs[]'
)
),
// arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string)
'tns:Stuffs'
);
$server->register(
// string $name the name of the PHP function, class.method or class..method
'getStuffs',
// array $in assoc array of input values: key = param name, value = param type
array(
'user' => 'xsd:string',
'pass' => 'xsd:string'
),
// array $out assoc array of output values: key = param name, value = param type
array(
'return' => 'tns:StuffsArray'
),
// mixed $namespace the element namespace for the method or false
'urn:' . $myNamespace,
// mixed $soapaction the soapaction for the method or false
'urn:' . $myNamespace . "#getStuffs",
// mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically
'rpc',
// mixed $use optional (encoded|literal) or false
'encoded',
// string $documentation optional Description to include in WSDL
'Fetch array of Stuffs ("id", "name").' // documentation
);
#$server->wsdl->schemaTargetNamespace = $myNamespace;
$server->service(isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '');
exit();
?>
в консольном приложении C# после добавления веб-ссылки под названием " StuffService "с"?wsdl " прилагается к соответствующему URL, где этот PHP-файл можно найти, этот код работает, я могу отлично запросить значения stuff_array следующим образом:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WebServiceTest
{
class Program
{
static void Main(string[] args)
{
StuffService.MyStuffService myService = new StuffService.MyStuffService();
StuffService.Stuffs[] stuffs = myService.getStuffs("someone", "1234");
foreach (var stuff in stuffs)
{
Console.WriteLine(stuff.id+".: "+stuff.name);
}
Console.WriteLine();
Console.WriteLine("Press a key...");
Console.ReadKey();
}
}
}
это круто, но я хотел бы разработать этот код, чтобы вернуть объект вот так:
class ResponseObject {
public $responseCode = 0;
public $responseMessage = '';
public $stuffArray = NULL;
}
$responseObject = NULL;
function getStuffs( $user='', $pass='' ) {
global $responseObject;
$responseObject = new ResponseObject();
// check stuffs in a simple way now
if($user != 'someone' && $pass != '1234'){
$responseObject->responseCode = 2;
$responseObject->responseMessage = 'Authentication failed';
return $responseObject;
}
$responseObject->stuffArray = array();
$responseObject->stuffArray[] = array( 'id'=>122, 'name'=>'One stuff');
$responseObject->stuffArray[] = array( 'id'=>213, 'name'=>'Another stuff');
$responseObject->stuffArray[] = array( 'id'=>435, 'name'=>'Whatever stuff');
$responseObject->stuffArray[] = array( 'id'=>65, 'name'=>'Cool Stuff');
$responseObject->stuffArray[] = array( 'id'=>92, 'name'=>'Wow, what a stuff');
$responseObject->responseCode = 1;
$responseObject->responseMessage = 'Successful!';
return $responseObject;
}
каков соответствующий код NuSOAP для этого?
Спасибо!! :)
надеюсь, я мог бы уточнить, чего я хотел бы достичь: возврат структуры, которая содержит int, строку и массив структур, но не знаю, как написать соответствующий nusoap-код для этого. Таким образом, я мог бы сначала проверить responseCode и обработать его с соответствующими сообщениями об ошибках или выводом stuffArray и т. д.
1 ответов
после долгих часов экспериментов, я нашел решение!
таким образом, возвращая структуру, содержащую три члена - int responseCode, string responseMessage и массив структур, называемых stuffArray в Примере-через SOAP с NUSOAP (PHP) выглядит следующим образом, я помещаю некоторые комментарии в код, чтобы сделать его более однозначным:
<?php
class ResponseObject {
public $responseCode = 0;
public $responseMessage = 'Unknown error!';
public $stuffArray = NULL;
}
/**
* @return object
*/
function getStuffs( $user='', $pass='' ) {
$responseObject = new ResponseObject();
// check stuffs in a simple way now
if( !($user == 'someone' and $pass == '1234') ){
$responseObject->responseCode = 2;
$responseObject->responseMessage = 'Authentication failed!';
return $responseObject;
}
$responseObject->stuffArray = array();
$responseObject->stuffArray[] = array( 'id'=>122, 'name'=>'One stuff');
$responseObject->stuffArray[] = array( 'id'=>213, 'name'=>'Another stuff');
$responseObject->stuffArray[] = array( 'id'=>435, 'name'=>'Whatever stuff');
$responseObject->stuffArray[] = array( 'id'=>65, 'name'=>'Cool Stuff');
$responseObject->stuffArray[] = array( 'id'=>92, 'name'=>'Wow, what a stuff');
$responseObject->responseCode = 1;
$responseObject->responseMessage = 'Successful!';
return $responseObject;
}
require_once 'nusoap/lib/nusoap.php';
$server = new soap_server;
// $myNamespace = $_SERVER['SCRIPT_URI'];
$myNamespace = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'];
$server->configureWSDL(
// string $serviceName, name of the service
'MyStuffService',
// mixed $namespace optional 'tns' service namespace or false
// 'urn:' . $myNamespace
$myNamespace
);
// $server->wsdl->schemaTargetNamespace = 'http://soapinterop.org/xsd/';
$server->wsdl->schemaTargetNamespace = $myNamespace;
$server->wsdl->addComplexType(
// name
'Stuffs',
// typeClass (complexType|simpleType|attribute)
'complexType',
// phpType: currently supported are array and struct (php assoc array)
'struct',
// compositor (all|sequence|choice)
'all',
// restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
'',
// elements = array ( name = array(name=>'',type=>'') )
array(
'id' => array(
'name' => 'id',
'type' => 'xsd:int'
),
'name' => array(
'name' => 'name',
'type' => 'xsd:string'
)
)
);
$server->wsdl->addComplexType(
// name
'StuffsArray',
// typeClass (complexType|simpleType|attribute)
'complexType',
// phpType: currently supported are array and struct (php assoc array)
'array',
// compositor (all|sequence|choice)
'',
// restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
'SOAP-ENC:Array',
// elements = array ( name = array(name=>'',type=>'') )
array(),
// attrs
array(
array(
'ref' => 'SOAP-ENC:arrayType',
'wsdl:arrayType' => 'tns:Stuffs[]'
)
),
// arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string)
'tns:Stuffs'
);
$server->wsdl->addComplexType(
// name
'ResponseObject',
// typeClass (complexType|simpleType|attribute)
'complexType',
// phpType: currently supported are array and struct (php assoc array)
'struct',
// compositor (all|sequence|choice)
'all',
// restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
'',
// elements = array ( name = array(name=>'',type=>'') )
array
(
'responseCode' => array( 'type' => 'xsd:int'),
'responseMessage' => array( 'type' => 'xsd:string'),
'stuffArray' => array( 'type' => 'tns:StuffsArray'
// DON'T UNCOMMENT THE FOLLOWING COMMENTED LINES, BECAUSE THIS WAY IT DOESN'T WORK!!! - Left it in the code not to forget it....
// ,
// 'minOccurs' => '0',
// 'maxOccurs' => 'unbounded'
)
)
);
$server->register(
// string $name the name of the PHP function, class.method or class..method
'getStuffs',
// array $in assoc array of input values: key = param name, value = param type
array(
'user' => 'xsd:string',
'pass' => 'xsd:string'
),
// array $out assoc array of output values: key = param name, value = param type
array(
'return' => 'tns:ResponseObject'
),
// mixed $namespace the element namespace for the method or false
// 'urn:' . $myNamespace,
$myNamespace,
// mixed $soapaction the soapaction for the method or false
// 'urn:' . $myNamespace . "#getStuffs",
$myNamespace . "#getStuffs",
// mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically
'rpc',
// mixed $use optional (encoded|literal) or false
'encoded',
// string $documentation optional Description to include in WSDL
'Fetch array of Stuffs ("id", "name").' // documentation
);
// $server->wsdl->schemaTargetNamespace = $myNamespace;
// function def.: nusoap/lib/class.soap_server.php (236)
$server->service(isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '');
// DON'T UNCOMMENT THE FOLLOWING LINES!! - Don't call these headers explicitly,
// everything will be handled in function service() appropriately - I know it by experience that it's not a good choice...
// output:wsdl
// header('Content-Type: text/xml;charset=utf-8');
// header('Content-Type: text/xml');
// echo $server->wsdl->serialize();
exit(0);
дайте этому файлу имя, например getStuffComplex.php
, а затем скопируйте этот файл где-нибудь на своем веб-сервере и запомните его путь.
Например, одно доменное имя на моем локальном веб-сервере -http://soap.local
, и вышеупомянутый PHP-код может быть достигнут по адресу http://soap.local/getStuffComplex.php
.
Допустим, вы хотите вызов функции getStuffs () в коде C# через клиент SOAP из консольного приложения в Visual Studio 2010. В этом случае необходимо выполнить следующие действия:
- создать новый проект консольного приложения
- щелкните правой кнопкой мыши "Ссылки" - "Добавить Служебная Справка"
- клик "дополнительно..."
- клик "Добавить Веб-Ссылку..."
- вставьте путь к ранее сохраненному URL-адресу PHP-файла (с содержимым выше) и добавьте "?строка "wsdl"в поле URL. Например в моем случае:
http://soap.local/getStuffComplex.php?wsdl
- щелкните зеленую стрелку вправо ("перейти") или нажмите Enter после заполнения поля URL. Если метод getStuff () найден, ситуация обнадеживающий.
- дайте ссылке имя с правой стороны (имя веб-ссылки), например "StuffServiceComplex" (я буду использовать это имя в моем коде), чем нажать Enter. Теперь вы должны увидеть его в "Веб-Ссылки".
- скопируйте код ниже в программу.cs, и проверить его, нажав F5 или нажав на зеленый значок "play".
в C# код:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Services.Protocols;
namespace WebServiceTestComplex
{
class Program
{
static void Main(string[] args)
{
try
{
StuffServiceComplex.MyStuffService myService = new StuffServiceComplex.MyStuffService();
StuffServiceComplex.ResponseObject myRespObject = myService.getStuffs("someone", "1234");
switch (myRespObject.responseCode)
{
// Everything was OK, results can be output
case 1:
Console.WriteLine("Everything's OK, let's write the results to the standard output:");
foreach (var stuff in myRespObject.stuffArray)
{
Console.WriteLine("\t"+stuff.id + ".:\t" + stuff.name);
}
break;
// Authentication failed
case 2:
// Unknown error
case 0:
default:
Console.WriteLine("Error:");
Console.WriteLine("\tError code: "+myRespObject.responseCode);
Console.WriteLine("\tError message: " + myRespObject.responseMessage);
break;
}
}
catch (SoapException e)
{
Console.WriteLine("=== SOAP EXCEPTION!! ===");
Console.WriteLine(e);
}
catch (Exception e)
{
Console.WriteLine("=== OTHER EXCEPTION!! ===");
Console.WriteLine(e.ToString());
}
Console.WriteLine();
Console.WriteLine("Press a key...");
Console.ReadKey();
}
}
}
вывод:
Everything's OK, let's write the results to the standard output:
122.: One stuff
213.: Another stuff
435.: Whatever stuff
65.: Cool Stuff
92.: Wow, what a stuff
Press a key...
Я надеюсь, что это помогает тому, кто боролся с объединением PHP, SOAP и .NET.
(Примечание: позаботьтесь о кодировании символов при использовании акцентов или любых специальных букв. По умолчанию можно использовать ANSI (но кодировки символов должны быть одинаковыми).)