代码改变世界

关于SOAPpy传递对象参数调用WebService的问题总结

2008-12-01 00:37  Jaypei  阅读(5433)  评论(6编辑  收藏  举报

第一次使用SOAPpy传递对象,谁知遇到了好多麻烦的问题,于是网上搜啊搜,找到了CPyUGqgg的一篇“使用SOAPpy的体会,借鉴了一些经验,得到一些启发,感谢qgg

SOAPpy调用.net写的WebService为例。

UserInfo.py
public class UserInfo
{
    
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
[WebService(Namespace = "http://testwebservice.localhost/")]
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;
    }

 

描述格式如下:
POST /t_web/UserService.asmx HTTP/1.1
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>

 

在构建对象时,刚开始我简单的这么想的:

class UserInfo(object):
    pass
...
= UserInfo()
u.UserName 
= "jaypei"
u.Password 
= "*************"
u.Birthday 
= SOAPpy.dateTimeType((2008,1,1,0,0,0))
u.Salary 
= 10
发送结果:
<?xml version="1.0" encoding="UTF-8"?>
<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">&lt;__main__.UserInfo object at 0x00D8C190&gt;</user>
</ns1:Register>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

 

 

看来需要实现__str__函数,但是这么做在逻辑层牵扯到SOAP的传递格式了,显然不会是它本意。

 

于是看Demo里面发现了SOAPpy.types。于是,模仿demo改了一下程序:

= SOAPpy.structType()
u._addItem(
'UserName''jaypei')
u._addItem(
'Password''************')
u._addItem(
'Birthday', SOAPpy.dateTimeType((2008,1,1,0,0,0)))
u._addItem(
'Salary'10)
发送结果:
<?xml version="1.0" encoding="UTF-8"?>
<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写成:

class UserInfo(SOAPpy.bodyType):
    _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)