Good evening, I have the following XML:
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<project xmlns="">
<title>MyProject</title>
<nodes>
<node>
<name>base</name>
<class>BaseNode</class>
</node>
<node>
<name>detail</name>
<class>DetailNode</class>
</node>
...
</nodes>
</project>
... that I'd wish to deserialize into the following object structure, so that a Project
contains a "Title" and a NodeCollection
(which in turn contains multiple Node
elements):
[DataContract(Name = "project")]
class Project
{
[DataMember(Name = "title")]
public string Title { get; set; }
[DataMember(Name = "nodes")]
public NodeCollection Nodes { get; set; }
}
[CollectionDataContract(Name = "nodes", ItemName = "node")]
class NodeCollection : List<Node>
{
}
[DataContract(Name = "node")]
class Node
{
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "class")]
public string Class { get; set; }
}
With this architecture, deserialization completes without errors, returning an expected Project
object, but:
The Title property on the Project object is set to the expected value, but the NodeCollection is always empty. In fact, it's not even initialized:
Object reference not set to an instance of an object
For some odd reason, the deserializer "does not recognize any nodes". I tried adding the KnownType
attribute, no success.
What am I doing wrong?
It works if you specify the Namespace
and Order
attributes; otherwise it complains about unexpected namespaces or fails to read the node(s) entirely, and for some reason it's expecting Title
to come after Nodes
.
[DataContract(Name = "project", Namespace="")]
public class Project
{
[DataMember(Name = "title",Order=1)]
public string Title { get; set; }
[DataMember(Name = "nodes", Order=2)]
public NodeCollection Nodes { get; set; }
}
[CollectionDataContract(Name = "nodes",Namespace="", ItemName = "node")]
public class NodeCollection : List<Node> { }
[DataContract(Name = "node", Namespace="")]
public class Node
{
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "class")]
public string Class { get; set; }
}
Looking at the documentation,
The basic rules for data ordering include:
- If a data contract type is a part of an inheritance hierarchy, data members of its base types are always first in the order.
- Next in order are the current type’s data members that do not have the Order property of the DataMemberAttribute attribute set, in alphabetical order.
- Next are any data members that have the Order property of the DataMemberAttribute attribute set. These are ordered by the value of the Order property first and then alphabetically if there is more than one member of a certain Order value. Order values may be skipped.
Because "N" comes before "T" alphabetically, it was expecting NodeCollection
to be first. Even though things are "out of order", it will still deserialize (which seems strange, but that's how it works) - it just will fill those objects/members with null.