The solution to this problem is to create a custom MessageInspector (via IClientMessageInspector) to inspect and alter the SOAP messages that the WCF client proxy produces, prior to sending them over the wire. The basis for this solution is articulated in Steven Cheng's post, "[WCF] How to modify WCF message via custom MessageInspector", with further background from Kirk Evan's post, "Modify Message Content with WCF".
I used the code from Steven's post to wire up the custom MessageInspector infrastructure. Then I modified his Transformf2() method, which operates only on the <Body>
portion of the SOAP message, to suit my particular needs. In my case, as described in the original question, I needed to define and use an alias for my target web service XML namespace, xmlns="http://tempuri.org"
, above.
To do this I must
- obtain a reference to the operation node,
<BankingTransaction>
, which will always be the first (and only) child of<Body>
- remove the attribute that sets the default namespace to the target namespace
- set the prefix (namespace alias) for the node
The modified Transform2() code that does this is below:
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;
}
}