4

我使用添加服务引用功能来创建外部 Web 服务的代理。

默认情况下,WCF 客户端正在生成 SOAP 消息,其中消息正文具有如下所示的命名空间装饰:

  <s:Body>
    <BankingTransaction xmlns="http://tempuri.org/">
      <amount>0</amount>
    </BankingTransaction>
  </s:Body>

我需要消息正文看起来像这样

  <s:Body>
    <bb:BankingTransaction xmlns:bb="http://tempuri.org/">
      <amount>0</amount>
    </bb:BankingTransaction>
  </s:Body>

区别在于“bb”xml 命名空间别名。我尝试使用的 Web 服务要求为消息有效负载的 xml 命名空间设置别名。WCF 客户端的默认行为是将命名空间定义为 DEFAULT 命名空间。我到处寻找解决这个问题的配置/装饰解决方案,但没有找到。除非有配置解决方案,否则我必须在序列化后检查和更改每条 SOAP 消息。#瘸。

这里有一个简单的解决方案吗?

4

1 回答 1

3

此问题的解决方案是创建一个自定义 MessageInspector(通过IClientMessageInspector)来检查和更改 WCF 客户端代理生成的 SOAP 消息,然后再通过线路发送它们。此解决方案的基础在 Steven Cheng 的帖子“[WCF] 如何通过自定义 MessageInspector 修改 WCF 消息”中进行了阐述,进一步的背景来自 Kirk Evan 的帖子“使用 WCF 修改消息内容”

我使用 Steven 帖子中的代码来连接自定义 MessageInspector 基础设施。然后我修改了他的 Transformf2() 方法,该方法只对<Body>SOAP 消息的一部分进行操作,以满足我的特殊需要。在我的情况下,如原始问题中所述,我需要为xmlns="http://tempuri.org"上面的目标 Web 服务 XML 命名空间定义和使用别名。

为此,我必须

  1. 获取对操作节点 的引用,该节点<BankingTransaction>始终是 的第一个(也是唯一的)子节点<Body>
  2. 移除将默认命名空间设置为目标命名空间的属性
  3. 设置节点的前缀(命名空间别名)

修改后的 Transform2() 代码如下:

   private static Message Transform(Message oldMessage)
    {
        //load the old message into XML
        var msgbuf = oldMessage.CreateBufferedCopy(int.MaxValue);

        var tmpMessage = msgbuf.CreateMessage();
        var xdr = tmpMessage.GetReaderAtBodyContents();

        var xdoc = new XmlDocument();
        xdoc.Load(xdr);
        xdr.Close();

        // We are making an assumption that the Operation element is the
        // first child element of the Body element
        var targetNodes = xdoc.SelectNodes("./*");

        // There should be only one Operation element
        var node = (null != targetNodes) ? targetNodes[0] : null;

        if (null != node)
        {
            if(null != node.Attributes) node.Attributes.RemoveNamedItem("xmlns");
            node.Prefix = "bb";
        }

        var ms = new MemoryStream();
        var xw = XmlWriter.Create(ms);
        xdoc.Save(xw);
        xw.Flush();
        xw.Close();

        ms.Position = 0;
        var xr = XmlReader.Create(ms);

        //create new message from modified XML document
        var newMessage = Message.CreateMessage(oldMessage.Version, null, xr);
        newMessage.Headers.CopyHeadersFrom(oldMessage);
        newMessage.Properties.CopyProperties(oldMessage.Properties);

        return newMessage;
    }
}
于 2013-02-25T15:55:55.627 回答