c# - 为自定义响应标头创建 wsdl
问题描述
我必须调用第三方 SOAP Web 服务。我正在使用 c#、Visual Studio 和 WCF。供应商无法为我提供 wsdl,所以我自己编写,然后使用我创建的 wsdl 添加服务引用。
这是一个示例请求:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<AuthHeader xmlns="http://sample.com/">
<Username>...</Username>
<Password>...</Password>
</AuthHeader>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<GetAttachment xmlns="http://sample.com/">
<AttachmentID >4851888</AttachmentID>
</Get>
</s:Body>
</s:Envelope>
这是一个示例响应:
<?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:Header>
<StatusType xmlns="http://sample.com/">
<StatusNumber>0</StatusNumber>
<Description>Success</Description>
</StatusType>
</soap:Header>
<soap:Body>
<GetAttachmentResponse xmlns="http://sample.com/">
{
..json content
}
</GetAttachmentResponse>
</soap:Body>
</soap:Envelope>
我创建的 wsdl 如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions 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://sample.com/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
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://sample.com/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:types>
<s:schema elementFormDefault="qualified" targetNamespace="http://sample.com/">
<s:element name="AuthHeader" type="tns:AuthHeader" />
<s:complexType name="AuthHeader">
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="Username" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="Password" type="s:string" />
</s:sequence>
<s:anyAttribute />
</s:complexType>
<s:element name="GetAttachment">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1" name="AttachmentID" type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="StatusHeader" type="tns:StatusHeader" />
<s:complexType name="StatusHeader">
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="StatusNumber" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="Description" type="s:string" />
</s:sequence>
<s:anyAttribute />
</s:complexType>
<s:element name="GetAttachmentResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1" name="Attachment">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="mimetype" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="filename" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="content" type="s:base64Binary" />
<s:element minOccurs="0" maxOccurs="1" name="description" type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
</s:sequence>
</s:complexType>
</s:element>
</s:schema>
</wsdl:types>
<wsdl:message name="GetAttachmentSoapIn">
<wsdl:part name="parameters" element="tns:GetAttachment" />
</wsdl:message>
<wsdl:message name="GetAttachmentSoapOut">
<wsdl:part name="response" element="tns:GetAttachmentResponse" />
</wsdl:message>
<wsdl:message name="GetAttachmentAuthenticationHeader">
<wsdl:part name="AuthenticationHeader" element="tns:AuthHeader" />
</wsdl:message>
<wsdl:message name="GetAttachmentStatusHeader">
<wsdl:part name="StatusHeader" element="tns:StatusHeader" />
</wsdl:message>
<wsdl:portType name="AttachmentsSOAP">
<wsdl:operation name="GetAttachment">
<wsdl:input message="tns:GetAttachmentSoapIn"/>
<wsdl:output message="tns:GetAttachmentSoapOut"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="AttachmentsSOAP" type="tns:AttachmentsSOAP">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="GetAttachment">
<soap:operation soapAction=""/>
<wsdl:input>
<soap:body use="literal" />
<soap:header message="tns:GetAttachmentAuthenticationHeader" part="AuthenticationHeader" use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
<soap:header message="tns:GetAttachmentStatusHeader" part="StatusHeader" use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="ApplyV1">
<wsdl:port name="AttachmentsSOAP" binding="tns:AttachmentsSOAP">
<soap:address location="https://api.sample.com/service"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
当我添加服务引用时,生成的代理类包含我期望的 GetAttachment 函数。问题是响应标头作为函数返回类型返回,soap 信封的实际响应(主体)作为输出参数返回:
public AttachmentAPI.StatusHeader GetAttachment(AttachmentAPI.AuthHeader AuthHeader, AttachmentAPI.GetAttachment GetAttachment1, out AttachmentAPI.GetAttachmentResponse GetAttachmentResponse) {...}
我可以调用 GetAttachment 函数,它正确地进行了一次肥皂调用。soap 服务返回一个结果,并将结果反序列化为 GetAttachmentResponse 对象,而不是 StatusHeader 对象。理想情况下,签名看起来像......
public AttachmentAPI.GetAttachmentResponse GetAttachment(AttachmentAPI.AuthHeader AuthHeader, AttachmentAPI.GetAttachment GetAttachment) {...}
...其中 AttachmentAPI.GetAttachmentResponse 包含响应正文和自定义响应标头。任何帮助表示赞赏。
解决方案
我解决了这个问题,主要是通过将正确的部分放入消息中,并从 portType 和绑定中引用消息。这确实起作用,尽管它仍然会导致 Visual Studio 生成一个代理类,我认为这是一个不受欢迎的函数签名。header 对象从函数返回,响应体反序列化的对象作为 out 参数返回:
public AttachmentAPI.StatusResponseHeaderType GetAttachment(AttachmentAPI.AuthRequestHeaderType AuthHeader, AttachmentAPI.GetAttachment GetAttachment1, out AttachmentAPI.GetAttachmentResponse GetAttachmentResponse) {...}
但至少它起作用了,我可以检索状态标题和实际的正文内容。
这是我修改后的wsdl:
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions 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://sample.com/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
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://sample.com/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:types>
<s:schema elementFormDefault="qualified" targetNamespace="http://sample.com/">
<s:element name="AuthHeader" type="tns:AuthRequestHeaderType" />
<s:complexType name="AuthRequestHeaderType">
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="Username" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="Password" type="s:string" />
</s:sequence>
<s:anyAttribute />
</s:complexType>
<s:element name="StatusType" type="tns:StatusResponseHeaderType" />
<s:complexType name="StatusResponseHeaderType">
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="StatusNumber" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="Description" type="s:string" />
</s:sequence>
<s:anyAttribute />
</s:complexType>
<s:element name="GetAttachment">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1" name="AttachmentID" type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="GetAttachmentResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1" name="Attachment">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="mimetype" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="filename" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="content" type="s:base64Binary" />
<s:element minOccurs="0" maxOccurs="1" name="description" type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
</s:sequence>
</s:complexType>
</s:element>
</s:schema>
</wsdl:types>
<wsdl:message name="GetAttachmentSoapIn">
<wsdl:part name="AuthenticationHeader" element="tns:AuthHeader" />
<wsdl:part name="parameters" element="tns:GetAttachment" />
</wsdl:message>
<wsdl:message name="GetAttachmentSoapOut">
<wsdl:part name="StatusHeader" element="tns:StatusType" />
<wsdl:part name="response" element="tns:GetAttachmentResponse" />
</wsdl:message>
<!--<wsdl:message name="GetAttachmentAuthenticationRequestHeaderMessage">
<wsdl:part name="AuthenticationHeader" element="tns:AuthHeader" />
</wsdl:message>
<wsdl:message name="GetAttachmentStatusResponseHeaderMessage">
<wsdl:part name="StatusHeader" element="tns:StatusHeader" />
</wsdl:message>-->
<!-- PortType defines the abstract interface of a web service.
Port type is implemented by the binding and service elements -->
<wsdl:portType name="AttachmentsSoap">
<wsdl:operation name="GetAttachment">
<wsdl:input message="tns:GetAttachmentSoapIn"/>
<wsdl:output message="tns:GetAttachmentSoapOut"/>
</wsdl:operation>
</wsdl:portType>
<!-- the binding specifies concrete implementation details and
essentially maps a portType to a set of protocols (HTTP and SOAP)
message styles (Document/RPC) and encodings (literal) -->
<wsdl:binding name="AttachmentsSoap" type="tns:AttachmentsSoap">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="GetAttachment">
<soap:operation soapAction=""/>
<wsdl:input>
<soap:header message="tns:GetAttachmentSoapIn" part="AuthenticationHeader" use="literal" />
<soap:body use="literal" parts="parameters" />
</wsdl:input>
<wsdl:output>
<soap:header message="tns:GetAttachmentSoapOut" part="StatusHeader" use="literal" />
<soap:body use="literal" parts="response"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="ApplyV1">
<wsdl:port name="AttachmentsSoap" binding="tns:AttachmentsSoap">
<soap:address location="https://api.sample.com/soap/apply/v1"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
推荐阅读
- android - 在水平滚动视图的回收器视图中显示超过 5 列
- xamarin - 使用动态资源或指定确切数字的 Xamarin Forms 的 Android 绘制性能?
- input - ffpmeg 强制覆盖(严重)检测到的输入帧率
- css - CSS 背景图片 - 如何设置图片停留在原位
- laravel - 为什么按计划运行的日志:在 Laravel Vapor 上运行而不保存在 Cloudwatch 中?
- reactjs - 如何让组件在 React 中只加载一次?
- blockchain - 我如何在区块链网络上部署我的合约?
- rust - 在 Rust 中将方法作为参数提供(Vec sort() 方法)
- gcc - 使用 map 并使用 clang 编译时未定义的引用 eeror [abi:cxx11]
- php - 获取 PHP 函数 (Symfony 4.2)