Почему массивы отображаются как нулевые после сериализации с использованием DataContractJsonSerializer?

Было несколько вопросов о сериализации и десериализации массивов с использованием DataContractJsonSerializer (включая один от меня: Как я могу сериализовать массив строк в JSON с помощью DataContractJsonSerializer?), но, похоже, ни один из них не отвечает на текущую проблему, с которой я столкнулся.

Я преобразовываю строку XML в строку JSON, десериализуя XML в объект DataContract, а затем сериализуя этот объект в JSON, используя DataContractJsonSerializer. Мой подход такой же, как я использовал для ряда других объектов, все из которых отлично сериализуются в JSON, но у меня есть объект, в котором свойство массива всегда отображается как null после сериализации.

Классы определяются следующим образом:

[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; }
}

XML, который я использую, выглядит следующим образом:

<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>

Десериализация и сериализация выполняются следующими методами:

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;
    } 
}

Когда я тестирую его, свойство Consignments всегда имеет значение null в результирующем JSON.

"order": {
  "consignments": [
    {
      "conh_id": null,
      "conh_status": null,
      "consignmententries": null
    }
  ]
}

Отладка показывает, что это свойство имеет значение null в объекте, созданном после шага десериализации, поэтому проблема заключается в десериализации XML, а не в сериализации JSON.

Что мне нужно изменить в моей объектной модели, чтобы правильно преобразовать массив?


person Valerie Metcalf    schedule 18.11.2015    source источник


Ответы (1)


Ваша проблема возникает при десериализации из XML, а не при сериализации в JSON. В вашем XML коллекции были сериализованы на двух уровнях: элемент внешнего контейнера и элемент для каждого элемента:

  <consignments>
    <consignment>
       <!-- Consignment data -->
    </consignment>
  </consignments>

И

  <consignmententries>
    <consignmententry>
       <!-- Entry data -->
    </consignmententry>
  </consignmententries>

(Для сравнения, в связанном вопросе коллекция Labels XML имеет один уровень). Таким образом, вам нужно использовать [XmlArray(string name)] и [XmlArrayItem(string itemName)], чтобы указать имена внешнего и внутреннего элемента:

[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; }
}

И наоборот, добавление атрибута [XmlElement] для коллекции сообщает XmlSerializer, что коллекция должна быть сериализована без элемента внешнего контейнера.

Вам также необходимо добавить [XmlRoot("order")] к Order, чтобы указать имя корневого элемента.

Теперь ваш XML будет успешно десериализован.

person dbc    schedule 18.11.2015
comment
dbc, это сработало отлично. Спасибо за ответ. Для всех, кто следит за этим, причина, по которой у меня возникли проблемы, заключалась в атрибуте «[XMLElement]» в свойствах моего массива. В других объектных моделях, которые я сериализовал и десериализовал, имена элементов XML соответствовали свойствам объекта, поэтому мне не нужен был этот атрибут. Именно этот атрибут заставил обрабатывать массивы не так, как я ожидал. - person Valerie Metcalf; 19.11.2015