添加选项以绕过多参数方法的ComplexType包装的最佳方法

2024-10-03 23:17:44 发布

您现在位置:Python中文网/ 问答频道 /正文

我们最近开始使用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阅读到这一点,感谢您的所有工作


Tags: nameinmessagestringtypepinpasswordelement
1条回答
网友
1楼 · 发布于 2024-10-03 23:17:44

裸方法不能有>;1个参数,这是SOAP限制

下面的代码有什么问题


class ObjResultadoBasico(ComplexModel):
    PError = Integer
    SError = Unicode


class UCDprovision_passwordRequest(ComplexModel):
    p_msisdn = Unicode
    p_pin = Unicode
    p_password = Unicode


class UCDService(ServiceBase):
    @rpc(UCDprovision_passwordRequest, _returns=ObjResultadoBasico,
         _body_style='bare')
    def UCDprovision_password(ctx, passreq):
        # ComplexModel doesn't support *args in its default ctor, use **kwargs
        # or use a custom ctor
        return ObjResultadoBasico(PError=1, SError=passreq.p_msisdn)


相关问题 更多 >