Modifying the Body of the Message
The modification of the body is a common task required in many applications. The Message Fixer explained in "Fixed the Messages" article performs body modification before the after the request is received and before the response is sent on the server side or before sending the request and after receiving the response on the client side. As explained in the article for smaller message one can create the XMLDocument from the message body by getting the Body reader from the message as shown below.
// Fix the request
XmlDocument doc = new XmlDocument();
doc.Load(request.GetBodyReader());
However recently while working on an Interop application I discovered that this quick an easy way of modifying the body of the messages did not work in cases when the body content had elements or attributes of QName type. Specifically if the namespace for the prefix used in the value of element or attribute was defined before the Body element. The XML processors typically do not poke at the values and hence they try their best to preserve the context at which the namespace was declared. In my case I was creating XML document from the Body element onwards. Hence if the namespace declaration was before the Body element, i..e at the Envelope level, which XML document never saw, the re declaration of the namespace occurred. The namespace was re declared when it was first used in the name of the element or attribute and NOT when it was used as the value of the element or attribute. For example, if an XML document was created from the Body reader of the Message object for the following message the namespace https://mynamespace was re declared after it was used in one of the attribute values. You can see how this can result in failure of parsing the values later on.
Original Message <s:Envelope xmlns:q="https://mynamespace" ...> <s:Body> <MyRequest xmlns="https://tempuri.org" MyAttr="q:myattrvalue"> <q:value2> </q:value2> </MyRequest> </s:Body><s:Envelope> | Processed Message<s:Envelope ...> <s:Body> <MyRequest xmlns="https://tempuri.org" MyAttr="q:myattrvalue"> <q:value2 xmlns:q="https://mynamespace"> </q:value2> </MyRequest> </s:Body><s:Envelope> |
So how does on modifies the message? The easiest way to do this would be to preserve the complete message and then perform the modification on the body. Note that this is applicable to small messages that you can fit reasonably in memory.
Write out the entire message as string
StringBuilder builder = new StringBuilder(); XmlWriter writer = XmlWriter.Create(builder); origMsg.WriteMessage(writer); writer.Close(); string origMsgStr = builder.ToString()
Perform the modifications on the string or create the DOM using XMLDocument.LoadXml method.
XmlDocument origMsgDoc = new XmlDocument(); origMsgDoc.LoadXml(origMsgStr); // modify the message
Recreate the message
XmlReader newMsgReader = XmlReader.Create(new StringReader(origMsgStr)); Message newMsg = Message.CreateMessage(newMsgReader, int.MaxValue);
Copy over the message properties
newMsg.Properties.CopyProperties(origMsg.Properties);