C# – Using XmlSerializer to serialize

Here’s how to serialize an object into XML using XmlSerializer:

static string GetXml(object obj) { XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType()); using (var writer = new StringWriter()) { xmlSerializer.Serialize(writer, obj); return writer.ToString(); } }
Code language: C# (cs)

You must add the [Serializable] attribute to the class you want to serialize:

[Serializable] public class Author { public string Name { get; set; } public List<string> Books { get; set; } public List<string> Influences { get; set; } public string QuickBio { get; set; } }
Code language: C# (cs)

Here’s an example of creating an Author object and feeding it to the serializer:

static void Main(string[] args) { var nnt = new Author() { Name = "Nassim Nicholas Taleb", Books = new List<string>() { "Fooled by Randomness", "Black Swan", "Antifragile", "Skin in the Game" }, Influences = new List<string>() { "Karl Popper", "Benoit Mandelbrot", "Daniel Kahneman", "F.A. Hayek", "Seneca", "Michel de Montaigne", "Nietzsche" }, QuickBio = "Antifragile option trader who capitalized on inevitable Black Swan stock market blow up, then wrote a series of books centered on Uncertainty." }; string xml = GetXml(nnt); Console.WriteLine(xml); }
Code language: C# (cs)

This outputs the following XML:

<?xml version="1.0" encoding="utf-16"?> <Author xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Name>Nassim Nicholas Taleb</Name> <Books> <string>Fooled by Randomness</string> <string>Black Swan</string> <string>Antifragile</string> <string>Skin in the Game</string> </Books> <Influences> <string>Karl Popper</string> <string>Benoit Mandelbrot</string> <string>Daniel Kahneman</string> <string>F.A. Hayek</string> <string>Seneca</string> <string>Michel de Montaigne</string> <string>Nietzsche</string> </Influences> <QuickBio>Antifragile option trader who capitalized on inevitable Black Swan stock market blow up, then wrote a series of books centered on Uncertainty.</QuickBio> </Author>
Code language: HTML, XML (xml)

This example showed how to use XmlSerializer with all the default settings. In this article, I’ll show how to customize the serialization in a few different scenarios. At the end, I’ll show how to use XmlWriter to get around a known XMLSerializer/AssemblyLoadContext bug in .NET.

Note: In this article, I am writing the XML to a string variable, not to a stream/file.

How to remove the namespace attribute

Before, the Author element has the xmlns namespace attribute:

<?xml version="1.0" encoding="utf-16"?> <Author xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
Code language: HTML, XML (xml)

To remove this, pass in the following XmlSerializerNamespaces object in the call to Serialize().

static string GetXml(object obj) { XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType()); using (var writer = new StringWriter()) { xmlSerializer.Serialize(writer, obj, new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty })); return writer.ToString(); } }
Code language: C# (cs)

Now the Author element doesn’t have the namespace attribute:

<?xml version="1.0" encoding="utf-16"?> <Author>
Code language: HTML, XML (xml)

Change the encoding from UTF-16 to UTF-8

Notice how the encoding says UTF-16?

<?xml version="1.0" encoding="utf-16"?>
Code language: HTML, XML (xml)

This is because StringWriter defaults to UTF-16. In order to change this, you have to subclass StringWriter and override the Encoding getter:

public class Utf8StringWriter : StringWriter { public override Encoding Encoding { get { return Encoding.UTF8; } } }
Code language: C# (cs)

Then use this subclass instead of StringWriter:

static string GetXml(object obj) { XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType()); using (var writer = new Utf8StringWriter()) { xmlSerializer.Serialize(writer, obj, new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty })); return writer.ToString(); } }
Code language: C# (cs)

This changed the encoding to UTF-8 in the XML header:

<?xml version="1.0" encoding="utf-8"?>
Code language: HTML, XML (xml)

Change the name of a serialized property

Let’s say you want the QuickBio property to show up as Bio when you serialize.

<QuickBio>Antifragile option trader who capitalized on inevitable Black Swan stock market blow up, then wrote a series of books centered on Uncertainty.</QuickBio>
Code language: HTML, XML (xml)

Use the XmlElement attribute on the QuickBio property and specify “Bio”:

[Serializable] public class Author { public string Name { get; set; } public List<string> Books { get; set; } public List<string> Influences { get; set; } [XmlElement("Bio")] public string QuickBio { get; set; } }
Code language: C# (cs)

The QuickBio property now appears as Bio in the XML:

<?xml version="1.0" encoding="utf-8"?> <Author> <Name>Nassim Nicholas Taleb</Name> <Books> <string>Fooled by Randomness</string> <string>Black Swan</string> <string>Antifragile</string> <string>Skin in the Game</string> </Books> <Influences> <string>Karl Popper</string> <string>Benoit Mandelbrot</string> <string>Daniel Kahneman</string> <string>F.A. Hayek</string> <string>Seneca</string> <string>Michel de Montaigne</string> <string>Nietzsche</string> </Influences> <Bio>Antifragile option trader who capitalized on inevitable Black Swan stock market blow up, then wrote a series of books centered on Uncertainty.</Bio> </Author>
Code language: HTML, XML (xml)

Exclude a property from serialization

Let’s say you don’t want to serialize the Influences property. To do that, you can add the XmlIgnore attribute:

[Serializable] public class Author { public string Name { get; set; } public List<string> Books { get; set; } [XmlIgnore] public List<string> Influences { get; set; } [XmlElement("Bio")] public string QuickBio { get; set; } }
Code language: C# (cs)

After this, the Influences no longer shows up in the XML:

<?xml version="1.0" encoding="utf-8"?> <Author> <Name>Nassim Nicholas Taleb</Name> <Books> <string>Fooled by Randomness</string> <string>Black Swan</string> <string>Antifragile</string> <string>Skin in the Game</string> </Books> <Bio>Antifragile option trader who capitalized on inevitable Black Swan stock market blow up, then wrote a series of books centered on Uncertainty.</Bio> </Author>
Code language: HTML, XML (xml)

How to not indent the XML

By default, XmlSerializer outputs indented XML. This is nice and human-readable. However, let’s say you want to remove the indenting.

To do this, you need to pass in an XmlWriter object to XmlSerializer and set Indent=false (it’s false by default when you use XmlWriter, but it’s good to be explicit), like this:

static string GetXml(object obj) { XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType()); using (var writer = new Utf8StringWriter()) { using (var xmlWriter = XmlWriter.Create(writer, new XmlWriterSettings() { Indent = false })) { xmlSerializer.Serialize(xmlWriter, obj, new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty })); return writer.ToString(); } } }
Code language: C# (cs)

As you wished, this output is a very unreadable, unindented XML string:

<?xml version="1.0" encoding="utf-8"?><Author><Name>Nassim Nicholas Taleb</Name><Books><string>Fooled by Randomness</string><string>Black Swan</string><string>Antifragile</string><string>Skin in the Game</string></Books><Bio>Antifragile option trader who capitalized on inevitable Black Swan stock market blow up, then wrote a series of books centered on Uncertainty.</Bio></Author>
Code language: HTML, XML (xml)

Now that you’re using XmlWriter and XmlWriterSettings, you can customize the serialization even more if you need to.

XmlSerializer + AssemblyLoadContext = Known bug in .NET Core

There’s a known bug in .NET where if you try to dynamically load an assembly that’s using XmlSerializer (and you’re using AssemblyLoadContext constructor parameter isCollectible=true), then you’ll get the following exception:

A non-collectible assembly may not reference a collectible assembly

One way around this bug is to use XmlWriter instead of XmlSerializer, like this:

static string GetXml(Author a) { using (var writer = new Utf8StringWriter()) { using (var xmlWriter = XmlWriter.Create(writer, new XmlWriterSettings() { Indent = true, })) { xmlWriter.WriteStartDocument(); xmlWriter.WriteStartElement(nameof(Author)); xmlWriter.WriteElementString(nameof(a.Name), a.Name); xmlWriter.WriteEndElement(); xmlWriter.WriteEndDocument(); xmlWriter.Flush(); return writer.ToString(); } } }
Code language: C# (cs)

This outputs the following XML:

<?xml version="1.0" encoding="utf-8"?> <Author> <Name>Nassim Nicholas Taleb</Name> </Author>
Code language: HTML, XML (xml)

If you need a general-purpose approach with XmlWriter that works on all types, then you have to use reflection and walk the object graph. However, if you know the types ahead of time, then you can make this very specific and simple (like the example above). It really depends on your situation.

Note: With XmlWriter, you don’t need to mark your class with the [Serializable] attribute. This means you can serialize any class, even third-party classes that don’t have that attribute. On the downside, XmlWriter doesn’t pay attention to any attributes (like XmlIgnore).

Leave a Comment