Partager via


WCF: BodyWriter and Raw XML Problems

I've been recently writing code with Windows Communication Foundation (WCF) using raw Message contracts. The purpose of raw Message contracts is to allow the developer to be in complete control of the format of the message that is received and sent by a service. This is a good choice for the project that I'm working on because I am dealing with legacy code that is not strongly typed and I need the flexibility to process messages with structures that may vary between calls. (This is of course less than ideal, but it allows legacy code to function in WCF while we refactor the code.)

WCF provides several options for writing XML into your message. The Message.CreateMessage() method accepts Object (which will automatically be serialized using the Xml Serializer), XmlReader, XmlDictionaryReader or BodyWriter. The BodyWriter object provides an event that you can override to implement your own serialization.

In the project that I was creating, the data for my Message was already in XML, so I thought my most efficient solution would be to implement a BodyWriter that would simply write the raw XML into the stream. So I created the following class:

     public class SimpleMessageBody : BodyWriter
    {
        string xmlContent;

        public SimpleMessageBody(string content)
            : base(true)
        {
            this.xmlContent = content;
        }

        protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
        {
            writer.WriteRaw(xmlContent);
        }
    }

I then used this class to be the input to the CreateMessage method as follows:

     message = Message.CreateMessage(MessageVersion.Default, 
                "https://tempuri.org/SomeMethod", new SimpleMessageBody(xml));

Much to my surprise, my XML content was automatically encoded in my method! However, if I opened an XmlReader on my XML content and passed the reader into the method, everything worked fine.

Eventually, I used the .NET Reflector utility to look deep inside the BodyWriter class. It turns out that the BodyWriter uses it's own special implementation of XmlWriter and when you look at this implementation, whenever you call the .WriteRaw() method, that method actually calls the .WriteText() method under the hood which ultimately encodes your raw XML!

It's possible that Microsoft wanted to prevent developers from writing raw XML into the message in order to prevent corruption, namespace conflicts or potential security violations. Unfortunately, this behavior does not appear to be clearly documented.

The only option appears to be to open an XmlReader and use the .WriteNode() method.

     protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
    {
        using (StringReader stringReader = new StringReader(xmlContent))
        {
            using (XmlReader xmlReader = XmlTextReader.Create(stringReader))
            {
                writer.WriteNode(xmlReader, true);
            }
        }
    }