【问题标题】:Delphi SOAP Envelope and WCFDelphi SOAP 信封和 WCF
【发布时间】:2010-03-18 20:12:13
【问题描述】:

我正在开发一个提供肥皂接口的系统。将使用该接口的系统之一是在 Delphi 7 中编写的。Web 服务是使用 WCF、基本 http 绑定、SOAP 1.1 开发的。

如果我使用 SOAP UI (JAVA),服务可以正常工作。但是Delphi似乎在这里做了一些特别的事情;)

这是消息在 SOAP UI 中的样子:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://services.xxx.de/xxx">
   <soapenv:Header/>
   <soapenv:Body>
      <ser:GetCustomer>
         <!--Optional:-->
         <ser:GetCustomerRequest> <!-- this is a data contract -->
            <ser:Id>?</ser:Id>
         </ser:GetCustomerRequest>
      </ser:GetCustomer>
   </soapenv:Body>
</soapenv:Envelope>

我不是 delphi 开发人员,但我开发了一个简单的测试客户端来看看出了什么问题。这就是 Delphi 作为 SOAP 信封发送的内容。

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:NS2="http://services.xxx.de/xxx">
    <NS1:GetCustomer xmlns:NS1="http://services.xxx.de/xxx">
      <GetCustomerRequest href="#1"/>
    </NS1:GetCustomer>
    <NS2:GetCustomerRequest id="1" xsi:type="NS2:GetCustomerRequest">
      <Id xsi:type="xsd:int">253</Id>
    </NS2:GetCustomerRequest>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

WCF 抛出德语错误... ;)

Es wurde das Endelement "Body" aus Namespace "http://schemas.xmlsoap.org/soap/envelope/" erwartet。 Gefunden wurde "元素 "NS2:GetCustomerRequest" aus 命名空间 "http://services.xxx.de/xxx""。 Zeile 1,位置 599。

意思类似

身体是预期的。但是找到了元素“NS2:GetCustomerReques”。

现在我的问题是:我能以某种方式改变 Delphi 创建信封的方式吗?或者是使 WCF 使用这种消息格式的方法吗?非常感谢任何帮助!

【问题讨论】:

  • 问题不在于 NS1 NS2 部分。问题是 Delphi 正在制作结构不正确的 XML。 Web 服务似乎期望 GetCustomerRequest 嵌套在 GetCustomer 中,但 Delphi 客户端没有嵌套 GetCustomerRequest 元素。我不知道如何解决它。您是否使用 WCF 服务中的 WSDL 生成了 Delphi 客户端?

标签: c# .net wcf delphi soap


【解决方案1】:

与这里的某些人似乎暗示的相反,Delphi 没有发送 invalid SOAP,它只是发送 RPC/Encoded SOAP。从所有xsi:type 属性中很容易识别。 RPC/Encoded 不符合 WS-I,但它仍然有效的 SOAP。

默认情况下,WCF 使用 Document/Literal/Wrapped SOAP 格式,Delphi 7 在服务器端根本无法处理,您必须在客户端进行一些调整。

最简单的解决方案是简单地告诉 Delphi 使用 Document/Literal 样式。您可以通过打开THttpRio.Converter.Options 中的soLiteralParams 来做到这一点。这告诉 Delphi 不要“展开”您所看到的参数。 “文档”方面是 Delphi WSDL 导入器通常可以解决的问题,因此您无需担心。

另一种解决方案是告诉 WCF 服务使用 RPC/Encoded 样式,您可以通过向服务添加以下属性来做到这一点:

[ServiceContract]
[XmlSerializerFormat(Style = OperationFormatStyle.Rpc,
    Use = OperationFormatUse.Encoded)]
public interface IMyService
{
    // etc.
}

不推荐使用第二种方法,因为正如我之前提到的,RPC/Encoded 不符合 WS-I,但大多数 SOAP 工具包都可以识别它,因此我将其列为一种可能性。

【讨论】:

    【解决方案2】:

    我只是做了其中的一个,最后我进行了一系列 stringreplace 调用来更改我的 XML 输出以去除内联名称空间并使其看起来像 SoapUI 的格式。是的,要做到这一点需要大量的手动黑客攻击。

    例如:

    创建 RIO 后,调用您自己的 BeforeExecute proc:

    ...
     EEUPSERTRIO.OnBeforeExecute := self.RIO_BeforeExecute;
    ...
    
    procedure TMyWrapper.RIO_BeforeExecute(const MethodName: string; var SOAPRequest: WideString);
    {
    Since Delphi isn't very good at SOAP, we need to fix the request so that the namespaces are correct.
    Basically, you take what Delphi gives you and try it in SoapUI.
    If yours doesn't work and SoapUI's version does, make yours look like theirs.
    }
    

    ... 现在去掉内联命名空间:

    SOAPRequest := StringReplace(SOAPRequest,' xmlns:NS1="http://services.xxx.de/xxx"','',[rfReplaceAll,rfIgnoreCase]);
    

    ... 很多。

    然后,您将使用包含所需命名空间的soap 标头替换。

    SOAPRequest := StringReplace(SOAPRequest,'xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"','xmlns:ns1="http://services.xyzcorp.com/xyz/EnterpriseEmployeeService_1_0" '+'xmlns:ns1="http://schemas.xyzcorp.com/TLOIntegration_HRO_Preview/TLOIntegration_1_0" ',[]);
    

    然后你可以重新注入好的:

      ReplaceTag(SOAPRequest,'<metaData>','ns1:');
      ReplaceTag(SOAPRequest,'<trackingId>','ns1:');
      ReplaceTag(SOAPRequest,'<srcSystem>','ns1:');
    

    最后,您可以通过使用 SoapUI 重新使用 WSDL 并让它托管一个模拟服务来轻松捕获您的 Delphi 输出。然后将您的应用程序指向它作为端点,它会捕获输出。
    或者,您可以使用 Fiddler 作为代理来捕获请求。

    【讨论】:

    【解决方案3】:

    Delphi 和 Java 框架使用不同的名称空间。使是否兼容的一种方法是拦截原始 xml 并将所有“NS2”更改为反序列化器期望的任何内容

    干杯

    【讨论】:

    • -1:对于符合标准的 SOAP 解析器,名称空间前缀根本不重要
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-23
    • 1970-01-01
    相关资源
    最近更新 更多