2011-08-08 10 views
8

Me gustaría consultar algunos productos vía SOAP generando WSDL con NuSOAP.
Sé que hay muchas preguntas relacionadas con el tema, pero no tuve éxito para adaptar los códigos a mi problema en particular.Generación de WSDL con NuSOAP - return struct con varios tipos (int, string, array of structs)

Tuve éxito en la generación de código WSDL que devuelve solo una matriz de estructuras (matriz asociativa) PERO Me gustaría devolver un objeto (struct) que contiene una variable entera, una variable de cadena Y una matriz de estructuras.

Así, este es el código que funciona para el retorno de una gran variedad de estructuras:

<?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(); 

?> 

En una aplicación de consola de C#, después de añadir una referencia Web llamado "StuffService" con el "? Wsdl" anexa a la URL apropiada en este archivo PHP se puede encontrar, este código funciona, puedo consultar a la perfección los valores stuff_array como este:

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(); 
     } 
    } 
} 

Eso está bien, pero me gustaría desarrollar este código para devolver un objeto como éste:

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; 
} 

Cuál es el código NuSOAP apropiada para eso?
Gracias! :)

Espero poder aclarar lo que me gustaría lograr: devolver una estructura que contiene un int, una cadena y una matriz de estructuras, pero no sé cómo escribir el código NuSOAP apropiado para eso. De esta manera, primero pude verificar el código de respuesta y manejarlo con los mensajes de error apropiados O con la salida del archivo stuffArray, etc.

Respuesta

11

Después de largas horas de experimentación, ¡encontré la solución!

Devolviendo una estructura que contiene tres miembros - un int responseCode, una cadena responseMessage y una matriz de estructuras llamada stuffArray en el ejemplo - a través de SOAP con NuSOAP (PHP) se ve más abajo, puse algunos comentarios en el código para que sea más ambigua:

<?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); 

dar a este archivo un nombre, por ejemplo getStuffComplex.php, y luego copiar este archivo en algún lugar de su servidor web, y recordar su paso.
Por ejemplo, un nombre de dominio en mi servidor web local es http://soap.local, y se puede acceder al código PHP mencionado anteriormente al http://soap.local/getStuffComplex.php.

Digamos que desea llamar a la función getStuffs() en un código C# a través de un cliente SOAP, desde una aplicación de consola en Visual Studio 2010. En este caso, usted tiene que hacer los siguientes pasos:

  1. Crear un nuevo proyecto de aplicación de consola
  2. Haga clic derecho "Referencias" - "Agregar referencia de servicio"
  3. Haga clic "Advanced ..."
  4. Haga clic 'Agregar referencia Web ...'
  5. pegar la ruta de URL de la PHP-archivo guardado previamente (con el contenido anterior) y anexar el '? Wsdl' cadena en el campo URL. Para ejemplo, en mi caso: http://soap.local/getStuffComplex.php?wsdl
  6. Haga clic en la flecha verde de la derecha ("Go") o pulsa enter después de llenado del campo de URL Si getStuff() se encuentra método, la situación es esperanzadora
  7. Dar la referencia a.. nombre en el lado derecho (nombre de referencia web), por ejemplo "StuffServiceComplex" (voy a utilizar este nombre en mi código), que presionar Enter. Ahora tiene que verlo en "Referencias web".
  8. Copie el código siguiente en Program.cs, y pruébelo presionando F5 o haciendo clic en el ícono verde "reproducir".

El código 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(); 
     } 
    } 
} 

La salida:

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... 

espero que esto ayude a alguien que tuvo problemas con traer PHP y SOAP y .NET juntos.

(Nota: tenga cuidado con la codificación de caracteres cuando use acentos o letras especiales. De manera predeterminada, se podría usar ANSI (pero las codificaciones de caracteres tienen que ser las mismas).)