jvance.com

.net, c#, asp.net, linq, htpc, woodworking

WCF Adds Root Node on IXmlSerializable Object

Posted in ASP.NET, C#, WCF by Jarrett on 7/26/2008 10:27:45 PM - CST

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>
  1. I've set the BodyStyle to Bare
  2. I've set the [XmlSerializerFormat] attribute
  3. I've tried putting [XmlRoot(null)] on the Entry class
The only thing that seems to work is changing the return type to XElement. This is really odd behavior of WCF. I can't find anything in the documentation as to why it is doing this.

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.

Comments

None.

Add Comment

Login using
Google Yahoo flickr AOL
and more
Or provide your details
Please enter your name. Please enter a valid email. Please enter a valid website.
Please supply a comment.
0.0 (0)
on 9/11/2008 7:25:59 PM - CST

Recent Entries

Valid XHTML 1.0 Strict
© Copyright 2024