Jean-Philippe Leclerc
Jean-Philippe Leclerc

Reputation: 6805

Modifying the outputted xml of a DataContractSerializer

My WCF service uses a DataContractSerializer to serialize my objects and send them to the client. I'm currently having a problem with the way the outputted xml is formatted.

I would need to:

  1. Get DataSerializer used by my WCF service

  2. Change it so it output xml like that:

    <node></node>
    

    instead of that

    <node />
    

So, how would I access my Serializer then how could I change its settings so it writes the full end element.

Upvotes: 2

Views: 1192

Answers (1)

carlosfigueira
carlosfigueira

Reputation: 87308

The DataContractSerializer (DCS) doesn't know (care?) how the XML Infoset which represents the serialized graph will be output - it delegates it to a XmlWriter. The writer is the one which can (or not) write an empty element as <a/> or <a></a> - since those two are (supposed to be) equivalent, the DCS will use any. But if you control the writer, then you can control the output. This is not too hard to do - simply create a writer which wraps another one, and delegate all overrides to the inner writer except the one to WriteEndElement() - in that one, call Write*Full*EndElement to ensure that empty elements won't be written. The code below has such implementation, and it will write out the full end element when using the new writer.

public class StackOverflow_6846012
{
    class MyWriter : XmlWriter
    {
        XmlWriter inner;
        public MyWriter(XmlWriter inner)
        {
            this.inner = inner;
        }

        public override void Close()
        {
            this.inner.Close();
        }

        public override void Flush()
        {
            this.inner.Flush();
        }

        public override string LookupPrefix(string ns)
        {
            return this.inner.LookupPrefix(ns);
        }

        public override void WriteBase64(byte[] buffer, int index, int count)
        {
            this.inner.WriteBase64(buffer, index, count);
        }

        public override void WriteCData(string text)
        {
            this.inner.WriteCData(text);
        }

        public override void WriteCharEntity(char ch)
        {
            this.inner.WriteCharEntity(ch);
        }

        public override void WriteChars(char[] buffer, int index, int count)
        {
            this.inner.WriteChars(buffer, index, count);
        }

        public override void WriteComment(string text)
        {
            this.inner.WriteComment(text);
        }

        public override void WriteDocType(string name, string pubid, string sysid, string subset)
        {
            this.inner.WriteDocType(name, pubid, sysid, subset);
        }

        public override void WriteEndAttribute()
        {
            this.inner.WriteEndAttribute();
        }

        public override void WriteEndDocument()
        {
            this.inner.WriteEndDocument();
        }

        public override void WriteEndElement()
        {
            this.inner.WriteFullEndElement();
        }

        public override void WriteEntityRef(string name)
        {
            this.inner.WriteEntityRef(name);
        }

        public override void WriteFullEndElement()
        {
            this.inner.WriteFullEndElement();
        }

        public override void WriteProcessingInstruction(string name, string text)
        {
            this.inner.WriteProcessingInstruction(name, text);
        }

        public override void WriteRaw(string data)
        {
            this.inner.WriteRaw(data);
        }

        public override void WriteRaw(char[] buffer, int index, int count)
        {
            this.inner.WriteRaw(buffer, index, count);
        }

        public override void WriteStartAttribute(string prefix, string localName, string ns)
        {
            this.inner.WriteStartAttribute(prefix, localName, ns);
        }

        public override void WriteStartDocument(bool standalone)
        {
            this.inner.WriteStartDocument(standalone);
        }

        public override void WriteStartDocument()
        {
            this.inner.WriteStartDocument();
        }

        public override void WriteStartElement(string prefix, string localName, string ns)
        {
            this.inner.WriteStartElement(prefix, localName, ns);
        }

        public override WriteState WriteState
        {
            get { return this.inner.WriteState; }
        }

        public override void WriteString(string text)
        {
            this.inner.WriteString(text);
        }

        public override void WriteSurrogateCharEntity(char lowChar, char highChar)
        {
            this.inner.WriteSurrogateCharEntity(lowChar, highChar);
        }

        public override void WriteWhitespace(string ws)
        {
            this.inner.WriteWhitespace(ws);
        }
    }
    public static void Test()
    {
        DataContractSerializer dcs = new DataContractSerializer(typeof(List<string>));
        MemoryStream ms = new MemoryStream();
        List<string> list = new List<string> { "Hello", "", "world" };
        dcs.WriteObject(ms, list);
        Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));

        Console.WriteLine();

        ms.SetLength(0);
        XmlWriter myWriter = new MyWriter(XmlDictionaryWriter.CreateTextWriter(ms));
        dcs.WriteObject(myWriter, list);
        myWriter.Flush();
        Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
    }
}

Now, the place where you'd hook up this writer in WCF would be a custom message encoder. The sample at http://msdn.microsoft.com/en-us/library/ms751486.aspx does exactly that - it replaces the default writer used by WCF with one from the System.Xml.dll assembly.

Upvotes: 2

Related Questions