我们最近开始使用Spyne,它看起来非常强大。在我们的例子中,我们需要复制一个我们正在替换的遗留SOAP API。为了确保与当前客户端的兼容性,我们希望spyne生成的WSDL与当前WSDL尽可能接近
如本问题所述:
How can I stop Spyne from wrapping arguments in a complexType?
Spyne将具有多个简单参数的方法的传入参数包装在ComplexType结构中
在遗留wsdl中,此操作
<operation name="UCDprovision_password" parameterOrder="p_msisdn p_pin p_password">
<input name="UCDprovision_passwordRequest" message="impl:UCDprovision_passwordRequest"/>
<output name="UCDprovision_passwordResponse" message="impl:UCDprovision_passwordResponse"/>
</operation>
与此消息相关:
<message name="UCDprovision_passwordRequest">
<part name="p_msisdn" type="xsd:string"/>
<part name="p_pin" type="xsd:string"/>
<part name="p_password" type="xsd:string"/>
</message>
这个复杂类型:
<complexType name="ObjResultadoBasico">
<sequence>
<element name="PError" type="xsd:int"/>
<element name="SError" nillable="true" type="xsd:string"/>
</sequence>
</complexType>
我们已创建以下spyne代码来复制该操作:
class ObjResultadoBasico(ComplexModel):
PError = Integer
SError = String
class UCDService(ServiceBase):
@rpc(String, String, String, _returns=ObjResultadoBasico, _in_message_name='UCDprovision_passwordRequest')
def UCDprovision_password(ctx,p_msisdn,p_pin,p_password):
return ObjResultadoBasico('1',p_msisdn)
这将生成以下WSDL(省略不相关的部分)
<xs:complexType name="ObjResultadoBasico">
<xs:sequence>
<xs:element name="PError" type="xs:integer" minOccurs="0" nillable="true"/>
<xs:element name="SError" type="xs:string" minOccurs="0" nillable="true"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="UCDprovision_passwordRequest">
<xs:sequence>
<xs:element name="p_msisdn" type="xs:string" minOccurs="0" nillable="true"/>
<xs:element name="p_pin" type="xs:string" minOccurs="0" nillable="true"/>
<xs:element name="p_password" type="xs:string" minOccurs="0" nillable="true"/>
</xs:sequence>
</xs:complexType>
<wsdl:operation name="UCDprovision_password" parameterOrder="UCDprovision_passwordRequest">
<wsdl:input name="UCDprovision_passwordRequest" message="tns:UCDprovision_passwordRequest"/>
<wsdl:output name="UCDprovision_passwordResponse" message="tns:UCDprovision_passwordResponse"/></wsdl:operation>
我们正在努力解决的不同点是,复杂类型包装了UCDprovision\u密码请求,该请求在遗留WSDL中被详细描述为
编辑:当请求消息以其自身的复杂类型预定义时,添加输出,因此操作本身可以使用“裸”样式,使用Burak Arslan建议的代码如下:
<xs:complexType name="UCDprovision_passwordRequest">
<xs:sequence>
<xs:element name="p_msisdn" type="xs:string" minOccurs="0" nillable="true"/>
<xs:element name="p_pin" type="xs:string" minOccurs="0" nillable="true"/>
<xs:element name="p_password" type="xs:string" minOccurs="0" nillable="true"/>
</xs:sequence>
</xs:complexType>
<xs:element name="UCDprovision_password" type="tns:UCDprovision_passwordRequest"/>
<wsdl:message name="UCDprovision_password">
<wsdl:part name="UCDprovision_password" element="tns:UCDprovision_password"/>
</wsdl:message>
此解决方案的问题在于,我不希望包装的不是操作本身,而是该操作的输入消息。我假设这是因为UCDprovision_passwordRequest(输入消息)被声明为ComplexModel
使用SOAPUI,以下是请求的示例:
旧WSDL
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ucd="http://UCD">
<soapenv:Header/>
<soapenv:Body>
<ucd:UCDprovision_pin>
<p_msisdn>?</p_msisdn>
<p_usuario>?</p_usuario>
<p_nemonico>?</p_nemonico>
<p_pin>?</p_pin>
</ucd:UCDprovision_pin>
</soapenv:Body>
</soapenv:Envelope>
Spyne WSDL
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ucd="UCD">
<soapenv:Header/>
<soapenv:Body>
<ucd:UCDprovision_pin>
<ucd:p_msisdn>?</ucd:p_msisdn>
<ucd:p_usuario>?</ucd:p_usuario>
<ucd:p_nemonico>?</ucd:p_nemonico>
<ucd:p_pin>?</ucd:p_pin>
</ucd:UCDprovision_pin>
</soapenv:Body>
</soapenv:Envelope>
最后,正如您所看到的,从客户机的角度来看,只有参数的名称空间是不同的,这可能是可以修复的(我还没有尝试过,您会怎么做?)
因为我们只需要接受客户端用旧WSDL发送的内容,所以我已经测试了“软”验证,并且Spyne代码(生成新WSDL)接受了用旧WSDL发送的请求
我们将继续测试,但我认为最终,除非不推荐,否则我将接受ComplexType定义并使用“软”验证,这解决了我们的问题。唯一的问题是如何在ComplexType属性中创建没有名称空间的WSDL
编辑:如果不需要修补程序,则以下文本不相关
正如上面的参考问题中所回答的,如果我们只有一个in_参数,我们可以在rpc decorator中使用_body_type='bare'来避免这种情况,但是对于0个或多个参数,spyne中不允许这样做。当然,我相信这是有充分理由的
综上所述,为了尽可能多地复制原始WSDL,我们希望开发一个补丁来添加将此多参数表示为WSDL的选项。如果可能的话,如果我们能够管理一个足够好的实现,我们还希望向上游贡献这个补丁
现在,我们要问的问题是:解决这个补丁的最佳方法是什么
在第一次回顾中,创建此XML段的代码是decorator.py中的以下代码:
message = None
if body_style_str == 'bare':
if len(in_params) > 1:
raise LogicError("body_style='bare' can handle at most one "
"function argument.")
if len(in_params) == 0:
message = ComplexModel.produce(type_name=in_message_name,
namespace=ns, members=in_params)
else:
message, = in_params.values()
message = message.customize(sub_name=in_message_name, sub_ns=ns)
if issubclass(message, ComplexModelBase) and not message._type_info:
raise LogicError("body_style='bare' does not allow empty "
"model as param")
# there can't be multiple arguments here.
if message.__type_name__ is ModelBase.Empty:
message._fill_empty_type_name(ns, in_message_name,
"%s_arg0" % in_message_name)
else:
message = ComplexModel.produce(type_name=in_message_name,
namespace=ns, members=in_params)
message.__namespace__ = ns
我们向装饰器添加一个可选标志,并使用该标志来创建所需的消息对象,而不是执行ComplexType路由,这样就足够了吗?A洛杉矶:
if len(in_params) > 1:
if (parameters_as_message):
message = message.special_way_to_construct(type_name=in_message_name,
namespace=ns, members=in_params)
else:
raise LogicError("body_style='bare' can handle at most one "
"function argument.")
感谢您阅读到这一点,如果Burak Arslan阅读到这一点,感谢您的所有工作
裸方法不能有>;1个参数,这是SOAP限制
下面的代码有什么问题
相关问题 更多 >
编程相关推荐