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

时间:2013-02-24 20:34:34

标签: c# wcf xml-serialization wcf-client

我使用“添加服务引用”功能为外部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消息。 #lame。

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

1 个答案:

答案 0 :(得分:3)

此问题的解决方案是创建自定义MessageInspector (通过 IClientMessageInspector )以在发送之前检查和更改WCF客户端代理生成的SOAP消息通过电线。这个解决方案的基础在Steven Cheng的帖子"[WCF] How to modify WCF message via custom MessageInspector"中有所阐述,还有Kirk Evan的帖子"Modify Message Content with WCF"的进一步背景。

我使用了Steven的帖子中的代码来连接自定义的MessageInspector基础结构。然后我修改了他的Transformf2()方法,该方法仅在SOAP消息的<Body>部分运行,以满足我的特定需求。就我而言,正如原始问题中所述,我需要为上面的目标Web服务XML命名空间xmlns="http://tempuri.org"定义和使用别名。

要做到这一点,我必须

  1. 获取对操作节点<BankingTransaction>的引用, 这将永远是<Body>
  2. 的第一个(也是唯一的)孩子
  3. 删除将默认命名空间设置为目标的属性 命名空间
  4. 为节点
  5. 设置前缀(名称空间别名)

    执行此操作的修改后的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;
        }
    }