最近一个项目由“winform直接访问db2”移植到“winform通过php web service来访问db2”。
(优点是php可以架在linux上,而linux是免费的)
这个命题的难点不是访问db2,而是.net调用php的web service。对于我这个长期作.net,之前一直以为只有.net才可以做web service……的人来说,真是有点强“聪”所难了。
但是问题还是要解决的,期限就摆在眼前呢。经过一番调查,终于有了眉目,现在分享给大家。
首先要说明的,php服务器需要至少需要两个文件——一个wsdl文件和一个php文件。wsdl文件是一种机读的xml文件,用于描述webservice提供的服务和调用方法(对于.net则可以自动生成调用代码,十分好用),php文件就是真正实现的web服务了。
1)php服务器端代码
1-1)testwebservice.php代码
以下为引用的内容:
<?php
class testwebservice
{
public function helloworld()
{
return array("helloworldresult"=>hello);
}
public function getarray($args)
{
/*
注意,web service的方法在声明时至多一个参数,
可是在调用该方法时就必须传value1,value2两个参数。
(这一点十分令人费解,我的理解是,在调用该方法时,系统把所有参数都放到一个对象里传过来的)
*/
$value1 = $args->value1;
$value2 = $args->value2;//这两句是获取真正的参数
$arry = array($value1,$value2);
//返回值也很特别,不是直接返回$arry,而是把它放到一个对象里再返回。
return array(getarrayresult=>$arry);
}
}
//创建websevice实例
$server = new soapserver(testwebservice.wsdl);
//指定类名
$server->setclass(testwebservice);
$server->handle();
?>
1-2)testwebservice.wsdl代码
以下为引用的内容:
<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tm="http://microsoft.com/wsdl/mime/textmatching/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="http://tempuri.org/" xmlns:s="http://www.w3.org/2001/xmlschema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" targetnamespace="http://tempuri.org/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:types>
<s:schema elementformdefault="qualified" targetnamespace="http://tempuri.org/">
<s:element name="helloworld">
<s:complextype />
</s:element>
<s:element name="helloworldresponse">
<s:complextype>
<s:sequence>
<s:element minoccurs="0" maxoccurs="1" name="helloworldresult" type="s:string" />
</s:sequence>
</s:complextype>
</s:element>
<s:element name="getarray">
<s:complextype>
<s:sequence>
<s:element minoccurs="0" maxoccurs="1" name="value1" type="s:string" />
<s:element minoccurs="0" maxoccurs="1" name="value2" type="s:string" />
</s:sequence>
</s:complextype>
</s:element>
<s:element name="getarrayresponse">
<s:complextype>
<s:sequence>
<s:element minoccurs="0" maxoccurs="1" name="getarrayresult" type="tns:arrayofstring" />
</s:sequence>
</s:complextype>
</s:element>
<s:complextype name="arrayofstring">
<s:sequence>
<s:element minoccurs="0" maxoccurs="unbounded" name="string" nillable="true" type="s:string" />
</s:sequence>
</s:complextype>
</s:schema>
</wsdl:types>
<wsdl:message name="helloworldsoapin">
<wsdl:part name="parameters" element="tns:helloworld" />
</wsdl:message>
<wsdl:message name="helloworldsoapout">
<wsdl:part name="parameters" element="tns:helloworldresponse" />
</wsdl:message>
<wsdl:message name="getarraysoapin">
<wsdl:part name="parameters" element="tns:getarray" />
</wsdl:message>
<wsdl:message name="getarraysoapout">
<wsdl:part name="parameters" element="tns:getarrayresponse" />
</wsdl:message>
<wsdl:porttype name="testwebservicesoap">
<wsdl:operation name="helloworld">
<wsdl:input message="tns:helloworldsoapin" />
<wsdl:output message="tns:helloworldsoapout" />
</wsdl:operation>
<wsdl:operation name="getarray">
<wsdl:input message="tns:getarraysoapin" />
<wsdl:output message="tns:getarraysoapout" />
</wsdl:operation>
</wsdl:porttype>
<wsdl:binding name="testwebservicesoap" type="tns:testwebservicesoap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="helloworld">
<soap:operation soapaction="http://tempuri.org/helloworld" style="document" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="getarray">
<soap:operation soapaction="http://tempuri.org/getarray" style="document" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:binding name="testwebservicesoap12" type="tns:testwebservicesoap">
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="helloworld">
<soap12:operation soapaction="http://tempuri.org/helloworld" style="document" />
<wsdl:input>
<soap12:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap12:body use="literal" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="getarray">
<soap12:operation soapaction="http://tempuri.org/getarray" style="document" />
<wsdl:input>
<soap12:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap12:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="testwebservice">
<wsdl:port name="testwebservicesoap" binding="tns:testwebservicesoap">
<soap:address location="http://localhost/phpmyadmin/ws/testwebservice.php" />
</wsdl:port>
<wsdl:port name="testwebservicesoap12" binding="tns:testwebservicesoap12">
<soap12:address location="http://localhost/phpmyadmin/ws/testwebservice.php" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
wsdl的代码比较长,当方法很多时,手敲代码是不太可能的。有一个巧的办法,就是也用.net实现一个不含真正方法体的web serivce,然后通过http://***/testwebservice.asmx?wsdl的方法生成wsdl代码文件。
关于wsdl文件,我要说明特别说明两点:
(1)soap:address结点是声明webservice的地址,在部署时要改成相应地址;
(2)一维数组的声明类型为arrayoftype,字符串数组为arrayofstring。如果type不是简单类型,则type需要另外声明。
2).net客户端代码
先要添加web引用,地址为wsdl文件的http地址。
调用代码(c#)
以下为引用的内容:
//初始化webservice
localhost.testwebservice srv = new localhost.testwebservice();
//调第一个方法
string str = srv.helloworld();
//调第二个方法
string[] arry= srv.getarray(string1,string2);
总结: (一)php是一种弱类型语言,检查错误比较困难。array类型也与一般理解的数组不同,它也有类似hashtable的用法。
(二)php web service方法的传入参数、返回值都至多有一个,因为真正调用时的参数和返回值,都是包装到一个对象中传送的。
(三)php web service也支持自定义类型和自定义类型数组等复杂类型,但不支持多组数组。
(四)若返回值需要是多张二维表时,我浅薄的以为,可以传化一组字符串数组传送,格式为
[表1行数],[表1列数],[表1列名1],[表1列名2],……[表1列名n],[表1中按行列存放的值]
[表2行数],[表2列数],[表2列名1],[表2列名2],……[表2列名n],[表2中按行列存放的值]
……
[表m行数],[表m列数],[表m列名1],[表m列名2],……[表m列名n],[表2中按行列存放的值]
以上就是.net调php web service的典型例子的内容。
