强制WCF在客户端代理中创建xml命名空间别名

本文关键字:创建 xml 命名空间 别名 代理 WCF 客户端 强制 | 更新日期: 2023-09-27 18:00:45

我使用添加服务引用功能创建了一个外部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消息#瘸的

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

强制WCF在客户端代理中创建xml命名空间别名

此问题的解决方案是创建一个自定义MessageInspector(通过IClientMessageInspector),以检查和更改WCF客户端代理生成的SOAP消息,然后再通过有线发送这些消息。这个解决方案的基础在Steven Cheng的文章"[WCF]How to modifying WCF message via custom MessageInspector"中有详细阐述,背景来自Kirk Evan的文章"modify message Content with WCF"。

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

要做到这一点,我必须

  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;
    }
}