INTERNET APPLICATION DEVELOPMENT
MID MARKET ERP DEVELOPMENT
by Derek Du
I use .NET XML serialization a lot and sometimes struggle with marking the nested classes with attributes to serialize correctly. How the serialization works seem to be tricky at first glance, although I can get it right with trial and error. That’s not optimal. I decided it’s time to make a summary of the tips and tricks I learned through the recent projects.
Serialize a Class
I have this class that I want to serialize. It contains a collection of Project objects.
I instantiated the class and added two projects to it. It will be serialized to XML. Note that .NET takes the property name Projects as the XML array name and uses the object type Project as array item name.
If I want to change the name of array to ‘Ps‘ and array item to ‘P‘, mark the class like this:
This generates an XML like this:
This poses a problem. Since it specifies the name of the array item on the collection, what if I want to change the array item’s name based on the member’s type? This will be a common request if we are serializing a generic class that can contain any type of collection member. I need a way to specify the array item’s name on the collection’s member instead of on the collection itself.
So I take off the [XmlArrayItem("P")] first. Now, how do I specify the name on the Project class? One may think marking the Project class with [XmlRoot("P")] could achieve this, but XmlRoot only works when the object is serialized as the root element. The correct way is to use [XmlType("P")] instead. The following class definition allows the XML to be serialized to the same XML above, but we have the flexibility of specifying the array item name for each type of collection member.
Up to this point, I serialized the projects property as a collection, with the array name at the top level and array item names at the second level. What if I want to place the element of array items under root level? Can I just “ignore” the property projects and directly serialize the collection members? In other words, how do I serialize to this XML?
Marking the property [XmlIgnore] seems to be an intuitive way to do it but it will result in the collection projects not being serialized at all. The correct way is to mark the property with [XmlElement()]. This class definition generates the above XML we want.
Now we face a similar challenge here – how to have member specific name if I want to serialize a generic object? The element name it is serialized to currently is specified on the collection projects side, not on the Project object’s side, which limits us from having an element name for each type of collection member.
In my research, I didn’t find a different place to put the attribute or a different attribute to achieve this. However, this can be achieved by XmlAttributeOverrides, which can dynamically overwrite the attribute on the run!
So what I want to achieve here is just to override the attribute of property projects to be [XmlElement("A_Dynamic_Name")]. This snippet demonstrates how to use XmlAttributeOverrides to do this.
This code generates a temporary class definition to be serialized. This allows us to dynamically get the type name of the collection member and use it as the element name.
And this is serialized to this XML:
As a side note, I also can use this to override the root element with a little modifications.
This blog originally appears in Derek's Blog, Stuff.