强制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消息#瘸的
这里有简单的解决方案吗?
此问题的解决方案是创建一个自定义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"
定义并使用别名。
要做到这一点,我必须
- 获得对操作节点
<BankingTransaction>
的引用,它将始终是<Body>
的第一个(也是唯一的)子代 - 删除将默认命名空间设置为目标的属性命名空间
- 设置节点的前缀(命名空间别名)
修改后的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;
}
}