There have been a number of questions about serializing and deserializing arrays using DataContractJsonSerializer (including one from me: How can I serialise a string array to JSON using DataContractJsonSerializer?) but none seem to answer the current problem that I'm having.
I am converting an XML string to a JSON string by deserializing the XML to a DataContract object and then serializing that object to JSON, using DataContractJsonSerializer. My approach is the same as I have used on a number of other objects, all of which are serializing to JSON perfectly, but I have an object in which an array property is always rendered as null after serialization.
The classes are defined as follows:-
[DataContract]
public class Order
{
[DataMember(Name = "consignments")]
[XmlElement("consignments")]
public Consignment[] Consignments { get; set; }
}
[DataContract]
public class Consignment
{
[DataMember(Name = "conh_id")]
[XmlElement("conh_id")]
public string ConsignmentHeaderId { get; set; }
[DataMember(Name = "conh_status")]
[XmlElement("conh_status")]
public string ConsignmentHeaderStatus { get; set; }
[DataMember(Name = "consignmententries")]
[XmlElement("consignmententries")]
public ConsignmentEntry[] ConsignmentEntries { get; set; }
}
The XML I'm using looks like this:-
<order>
<consignments>
<consignment>
<conh_id>A19708176</conh_id>
<conh_status>ACCEPTED</conh_status>
<consignmententries>
<consignmententry>
<conl_lineNbr>10000</conl_lineNbr>
<conl_sku>SEC01XXZBUXXX</conl_sku>
<conl_original_qty>1</conl_original_qty>
</consignmententry>
</consignmententries>
</consignment>
</consignments>
</order>
The deserializing and serializing is done in the following methods:-
private object DeserialiseXml(string xml)
{
var serialiser = new XmlSerializer(typeof(Order));
var stringReader = new StringReader(xml);
var result = serialiser.Deserialize(stringReader);
return result;
}
private string SerialiseJson(object serialisable)
{
using (MemoryStream stream = new MemoryStream())
{
var serialiser = new DataContractJsonSerializer(serialisable.GetType());
serialiser.WriteObject(stream, serialisable);
var json = Encoding.UTF8.GetString(stream.ToArray());
return json;
}
}
When I test it, the Consignments property is always null in the resulting JSON.
"order": {
"consignments": [
{
"conh_id": null,
"conh_status": null,
"consignmententries": null
}
]
}
Debugging shows that this property is null in the object created after the deserialization step so the problem is in the XML deserialization rather than the JSON serialization.
What do I need to change on my object model to get the array converted properly?
Your problem is happening when you deserialize from XML rather than when you serialize to JSON. In your XML, the collections have been serialized with two levels: an outer container element and an element for each item:
<consignments>
<consignment>
<!-- Consignment data -->
</consignment>
</consignments>
And
<consignmententries>
<consignmententry>
<!-- Entry data -->
</consignmententry>
</consignmententries>
(For comparison, in the linked question the Labels
XML collection has a single level). Thus you need to use [XmlArray(string name)]
and [XmlArrayItem(string itemName)]
to specify the outer and inner element names:
[DataContract]
[XmlRoot("order")]
public class Order
{
[DataMember(Name = "consignments")]
[XmlArray("consignments")]
[XmlArrayItem("consignment")]
public Consignment[] Consignments { get; set; }
}
[DataContract]
public class Consignment
{
[DataMember(Name = "conh_id")]
[XmlElement("conh_id")]
public string ConsignmentHeaderId { get; set; }
[DataMember(Name = "conh_status")]
[XmlElement("conh_status")]
public string ConsignmentHeaderStatus { get; set; }
[DataMember(Name = "consignmententries")]
[XmlArray("consignmententries")]
[XmlArrayItem("consignmententry")]
public ConsignmentEntry[] ConsignmentEntries { get; set; }
}
Conversely, adding the attribute [XmlElement]
to a collection tells XmlSerializer
that the collection should be serialized without the outer container element.
You also need to add [XmlRoot("order")]
to Order
to specify the root element name.
Now your XML will deserialize successfully.