Failure is inevitable

The System.Xml.XmlSerializer class enables .NET applications to serialize/deserialize most types to and from XML using only a few lines of code. This is a great capability and provides an easy API for simple persistence and interoperability scenarios. As a developer, you have some degree of control over the XML that’s generated, but the process is mostly rigid and not easy to extend or customize. There are also numerous “gotchas” around XML serialization, such as the inability to serialize IDictionary types, the inability to serialize and deserialize interfaces, and no support for the concept of “identity” when deserializing object graphs. Usually one can find a way around these limitations, but on a recent project I found that the pain of working around them was too great to bear. Out of that pain was born a new flexible XML serialization framework that overcomes the limitations of the XmlSerializer class. Read on to find out more.

XmlSerializer’s Abilities

XmlSerializer is a useful class that all .NET developers should be at least somewhat familiar with. Using it, you can easily transform most types to XML and back again, like this example from MSDN illustrates:

This is great for simple persistence scenarios, for making simple configuration settings files, and for providing interoperability with other systems. It is also very performant. The first time you construct a new XmlSerializer for a type, a custom serializer is emitted that can process the type without using reflection each time. This custom serializer is cached for the life of the application domain, and you can actually generate a serialization assembly if you want to avoid the performance hit the first time you serialize a new type each time your app runs.

XmlSerializer’s Inabilities

XmlSerializer is really quite useful for basic scenarios. However, like manythings in the .NET BCL, XmlSerializer was not built with extensibility in mind. To customize how it serializes a type, you have two options: use XML attributes or implement the IXmlSerializable interface and write your own serialization logic. If you try to use attributes to customize the behavior of XmlSerializer, you’ll quickly find that your control is very limited. You can ignore or rename properties and perform other such simple transformations, but that’s about it. The attribute-based approach also requires that you dirty up your objects with attributes, which some people consider a violation of the Single Responsibility Principle. If you want to customize something that isn’t supported by the very limited set of attributes, you’re out of luck unless you want to implement IXmlSerializable, and at that point you’re basically on your own for serializing your type.

Another weakness of XmlSerializer is that it has no concept of object identity. When deserializing an object graph, XmlSerializer will create a new instance for each object in the graph. It has no way of knowing that an object might appear in multiple locations in the XML.

XmlSerializer also doesn’t support serializing object graphs that contain cycles. You can use the XmlIgnore attribute to ignore properties that cause cycles, but that property will also be ignored when deserializing the object graph, which means you’ll have to manually rebuild properties in the object graph after XmlSerializer finishes.

Introducing Fluently-XML

One of the many projects I’m working on is a cost modeling system known as InGauge. InGauge uses XML to provide interoperability with other cost modeling tools. We’re dealing with very complex object graphs that must be correctly serialized and deserialized in order to maintain the integrity of the data as it passes from one system to another. Our team found that the limitations of XmlSerializer proved to be too painful to work around, so we created a custom XML serialization framework that gave us the control and flexibility we needed. Fluently-XML (that’s what I’m calling this framework) provides the same basic serialization/deserialization capabilities right out of the box as .NET’s XmlSerializer, but it also sports a fluent domain specific language (DSL) that can be used to customize the serialization and/or deserialization process for any type. It gives us complete control over how our object graphs are handled in a lightweight manner. Here are just a couple of things it currently provides beyond XmlSerializer:

This is the first of hopefully many posts on this framework. We’ll start in the next post by looking at the fluent DSL that can be used to customize the serialization/deserialization process and how it’s used to build up custom serialization behavior at runtime.

About Matt Honeycutt...

Matt Honeycutt is a software architect specializing in ASP.NET web applications, particularly ASP.NET MVC. He has over a decade of experience in building (and testing!) web applications.
He’s an avid practitioner of Test-Driven Development, creating both the SpecsFor and SpecsFor.Mvc frameworks.

He's also an author for Pluralsight,
where he publishes courses on everything from web applications to testing!