使用 NuSOAP 生成 WSDL - 返回各种类型的结构(int、字符串、结构数组)

发布于 2024-11-28 22:12:22 字数 6455 浏览 2 评论 0原文

我想通过使用 NuSOAP 生成 WSDL 来通过 SOAP 查询一些内容。
我知道有很多与该主题相关的问题,但我没有成功地使代码适应我的特定问题。

我成功生成了 WSDL 代码,该代码仅返回一个结构数组(关联数组),但是我宁愿返回一个包含整数变量、字符串变量和结构数组的对象(结构)。

因此,这是用于返回结构数组的代码

<?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”的 Web 引用并将“?wsdl”附加到相应的位置后可以找到此 PHP 文件的 URL,此代码有效,我可以完美地查询 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; 
}

What's theproperty NuSOAP code for那?
谢谢!! :)

我希望我能澄清我想要实现的目标:返回一个包含 int、字符串和结构数组的结构,但不知道如何为此编写适当的 NuSOAP 代码。这样我可以首先检查responseCode,并使用适当的错误消息或输出stuffArray等来处理它。

I would like to query some stuffs via SOAP by generating WSDL with NuSOAP.
I know there are lots of questions related to the topic, but I didn't have success to adapt the codes to my particular problem.

I was successful in generating WSDL code which returns just an array of structs (associative array), BUT I would rather like to return an object (struct) which contains an integer variable, a string variable AND an array of structs.

So, this is the code that works for returning an array of structs:

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

?>

In a C# Console Application, after adding a Web Reference called "StuffService" with the "?wsdl" appended to the appropriate URL where this PHP-file can be found, this code works, I can perfectly query the stuff_array values like this:

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

That's cool, BUT I'd like to develop this code to give back an object like this:

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

What's the appropriate NuSOAP code for that?
Thanks!! :)

I hope I could clarify what I would like to achieve: returning a struct which contains an int, a string and an array of structs, but don't know how to write the appropriate NuSOAP-code for that. This way I could firstly check the responseCode, and handle it with the appropriate error messages OR outputting the stuffArray, etc.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

清音悠歌 2024-12-05 22:12:22

经过长时间的实验,我找到了解决方案!

因此,返回一个包含三个成员的结构 - 一个 int responseCode、一个字符串 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,并且可以通过 http://soap.local/getStuffComplex.php 访问上述 PHP 代码

假设您想要通过 SOAP 客户端从 Visual Studio 2010 下的控制台应用程序中调用 C# 代码中的 getStuffs() 函数。在这种情况下,您必须执行以下步骤:

  1. 创建一个新的控制台应用程序项目
  2. 右键单击​​“引用”-“添加服务引用”
  3. 单击“高级...”
  4. 单击“添加 Web 引用...”
  5. 粘贴先前保存的 PHP 文件 URL 的路径(包含上述内容),并在 URL 字段中附加“?wsdl”字符串。例如,在我的例子中:http://soap.local/getStuffComplex.php?wsdl
  6. 单击绿色右箭头(“Go”)或在填写 URL 后按 Enter 键场地。如果找到 getStuff() 方法,情况就有希望了。
  7. 在右侧为引用命名(Web 引用名称),例如“StuffServiceComplex”(我将在代码中使用此名称),然后按 Enter 键。现在您必须在“Web 参考”下看到它。
  8. 将以下代码复制到 Program.cs 中,然后按 F5 或单击绿色“播放”图标进行测试。

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(但字符编码必须相同)。)

After long hours of experimentation, I found the solution!

So giving back a structure containing three members - an int responseCode, a string responseMessage and an array of structs called stuffArray in the example - via SOAP with NuSOAP (PHP) looks like this below, I put some comments in the code to make it more unambiguous:

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

Give this file a name, for example getStuffComplex.php, and then copy this file somewhere on your webserver, and remember its path.
For example one domain name on my local webserver is http://soap.local, and the above mentioned PHP-code can be reached at http://soap.local/getStuffComplex.php.

Let's say you want to call getStuffs() function in a C# code via a SOAP client, from a Console Application under Visual Studio 2010. In this case you have to do the following steps:

  1. Create a new Console Application project
  2. Right click "References" - "Add Service Reference"
  3. Click "Advanced..."
  4. Click "Add Web Reference..."
  5. Paste the path of the previously saved PHP-file's URL (with the content above) and append the "?wsdl" string in the URL field. For example in my case: http://soap.local/getStuffComplex.php?wsdl
  6. Click the green right arrow ("Go") or hit Enter after fill out URL field. If getStuff() method is found, the situation is hopeful.
  7. Give the reference a name on the right side (Web reference name), for example "StuffServiceComplex" (I will use this name in my code), than hit Enter. Now you have to see it under "Web References".
  8. Copy the code below into Program.cs, and test it by hitting F5 or clicking the green "play" icon.

The C# code:

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

The output:

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

I hope this helps someone who struggled with bringing PHP and SOAP and .NET together.

(Note: take care about character coding when using accents or any special letters. By default, ANSI could be used (but character encodings have to be the same).)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文