Jarrett's Tech Blog - Browsing WCF
-
WCF Adds Root Node on IXmlSerializable Object
Has anybody else had trouble with WCF adding a root node on their objects that implement IXmlSerializable?
Here is the setup:
- Create a class that implements IXmlSerializable
public class Entry : IXmlSerializable { public XElement Xml { get; set; } public void ReadXml(XmlReader reader) { Xml = XElement.Load(reader, LoadOptions.SetBaseUri); } public void WriteXml(XmlWriter writer) { Xml.WriteTo(writer); } }
- Create a WCF service that returns the object.
[ServiceContract] [XmlSerializerFormat] public interface IService { [OperationContract] [WebGet(BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "{a}/{b}/{c}")] Entry RetrieveEntry(string a, string b, string c); } public class Service: IService { public Entry RetrieveEntry(string a, string b, string c) { return new Entry { Xml = new XElement("test", a + "/" + b + "/" + c); } } }
When hitting the service located at http://localhost/EntryService.svc/one/two/three, I expect to get the following xml:<test>one/two/three</test>
Instead, I always get the above xml wrapped in a root node as shown below:<Entry xmlns="http://schemas.datacontract.org/2004/07/EntryTest"> <test>one/two/three</test> </Entry>
- I've set the BodyStyle to Bare
- I've set the [XmlSerializerFormat] attribute
- I've tried putting [XmlRoot(null)] on the Entry class
Update (7/27): It appears you must use the XmlRootAttribute to accomplish this. Your WriteXml(XmlWriter writer) method can check to see if the root node was already added by the serializer, and if not add it:
public void WriteXml(XmlWriter writer) { //only start document if needed bool start = false; if (writer.WriteState == WriteState.Start) { start = true; writer.WriteStartDocument(); writer.WriteStartElement("root", "http://example.com"); } //TODO: custom serialization here if (start) { writer.WriteEndElement(); writer.WriteEndDocument(); } }
This allows the WriteXml to be usable even when the object isn't being serialized by the WCF serializer.