第一次使用 SOAPpy传递对象,谁知遇到了好多麻烦的问题,于是网上搜啊搜,找到了 CPyUG中 qgg的一篇“使用 SOAPpy的体会” ,借鉴了一些经验,得到一些启发,感谢 qgg。
以 SOAPpy调用 .net写的 WebService为例。
UserInfo.py
{
protected string _userName;
protected string _password;
protected DateTime _birthday;
protected int _salary;
public string UserName
{
get { return this ._userName; }
set { this ._userName = value; }
}
public string Password
{
get { return this ._password; }
set { this ._password = value; }
}
public DateTime Birthday
{
get { return this ._birthday; }
set { this ._birthday = value; }
}
public int Salary
{
get { return this ._salary; }
set { this ._salary = value; }
}
}
UserService.cs
public class UserService : System.Web.Services.WebService {
…
[WebMethod]
public string Register(UserInfo user)
{
string result = string .Format( " Result : (UserName: {0}, Password: {1}, Birthday: {2}, Salary: {3}) " ,
user.UserName, user.Password, user.Birthday.ToString( " yyyy-MM-dd HH:mm:ss " ), user.Salary.ToString());
return result;
}
…
描述格式如下:
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://testwebservice.localhost/Register"
<? 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 >
< Register xmlns ="http://testwebservice.localhost/" >
< user >
< UserName > string </ UserName >
< Password > string </ Password >
< Birthday > dateTime </ Birthday >
< Salary > int </ Salary >
</ user >
</ Register >
</ soap:Body >
</ soap:Envelope >
在构建对象时,刚开始我简单的这么想的:
pass
...
u = UserInfo()
u.UserName = " jaypei "
u.Password = " ************* "
u.Birthday = SOAPpy.dateTimeType(( 2008 , 1 , 1 ,0,0,0))
u.Salary = 10
发送结果:
< SOAP-ENV:Envelope
SOAP-ENV:encodingStyle ="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENC ="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsi ="http://www.w3.org/1999/XMLSchema-instance"
xmlns:SOAP-ENV ="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd ="http://www.w3.org/1999/XMLSchema" >
< SOAP-ENV:Body >
< ns1:Register xmlns:ns1 ="http://testwebservice.localhost/" SOAP-ENC:root ="1" >
< user xsi:type ="xsd:UserInfo" > < __main__.UserInfo object at 0x00D8C190 > </ user >
</ ns1:Register >
</ SOAP-ENV:Body >
</ SOAP-ENV:Envelope >
看来需要实现__str__函数,但是这么做在逻辑层牵扯到SOAP的传递格式了,显然不会是它本意。
于是看Demo里面发现了SOAPpy.types。于是,模仿demo改了一下程序:
u._addItem( ' UserName ' , ' jaypei ' )
u._addItem( ' Password ' , ' ************ ' )
u._addItem( ' Birthday ' , SOAPpy.dateTimeType(( 2008 , 1 , 1 ,0,0,0)))
u._addItem( ' Salary ' , 10 )
发送结果:
< SOAP-ENV:Envelope
SOAP-ENV:encodingStyle ="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENC ="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsi ="http://www.w3.org/1999/XMLSchema-instance"
xmlns:SOAP-ENV ="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd3 ="http://www.w3.org/2001/XMLSchema"
xmlns:xsd ="http://www.w3.org/1999/XMLSchema" >
< SOAP-ENV:Body >
< ns1:Register xmlns:ns1 ="http://testwebservice.localhost/" SOAP-ENC:root ="1" >
< xsd:user >
< UserName xsi:type ="xsd:string" > jaypei </ UserName >
< Password xsi:type ="xsd:string" > ************ </ Password >
< Birthday xsi:type ="xsd3:dateTime" > 2008-01-01T00:00:00Z </ Birthday >
< Salary xsi:type ="xsd:int" > 10 </ Salary >
</ xsd:user >
</ ns1:Register >
</ SOAP-ENV:Body >
</ SOAP-ENV:Envelope >
还是报类型错误。于是仔细研究格式上的不同。
首先是user的命名空间不同,描述中的user是没有指定命名空间的,说明是默认命名空间,读了一下types.py的代码,发现anyType是类型的基类,刚刚用到的structType的继承关系是anyType - compoundType – structType ,再往下又发现了一个bodyType,于是想到UserInfo应该继承自bodyType才对。在anyType的__init__中有一个成员 _validURIs,默认赋了 (NS.XSD, NS.XSD2, NS.XSD3, NS.ENC),但是从代码中只看到用了 _validURIs[0]。
于是 UserInfo写成:
_validURIs = ( " http://testwebservice.localhost/ " , )
user 的 命名空间问题解决了,又请求发现还是格式不对,困惑了好半天忽然想到可能是参数的命名空间的问题,于是又翻查代码想看看参数的命名空间如何加。不知是没有 这接口还是我没找到,我就想了一个不是很漂亮的解决方法,就是注册Item的时候直接把命名空间写上(如果有谁知道的话请留言告诉我)。。
至此,终于搞定了,SOAPpy代码虽没细看但结构也看的差不多了 :)
调用代码如下:
from SOAPpy import WSDL
import SOAPpy
class UserInfo(SOAPpy.bodyType):
_validURIs = ( " http://testwebservice.localhost/ " , )
def main():
proxy = WSDL.Proxy( ' http://localhost:xxxx/UserService.asmx?WSDL ' )
# proxy.soapproxy.config.dumpSOAPOut = 1
# proxy.soapproxy.config.dumpSOAPIn = 1
proxy.methods[ ' Register ' ].namespace = ( " nsl " , " http://testwebservice.localhost/ " )
u = UserInfo()
u._addItem( " nsl:UserName " , " jaypei " )
u._addItem( " nsl:Password " , " ************* " )
u._addItem( " nsl:Birthday " , SOAPpy.dateTimeType(( 2008 , 1 , 1 ,0,0,0)))
u._addItem( " nsl:Salary " , 10 )
proxy.Register(user = u)