Как десериализовать динамическое свойство json для объекта? - PullRequest
1 голос
/ 19 июня 2019

Я пытаюсь десериализовать динамический JSON (из API) в правильные объекты, однако некоторые элементы не имеют типа.В примере JSON свойство «выполнение» имеет значения «F1» и «F2» и может иметь больше (проблема одна).В них свойства элемента имеют информацию о заказе продуктов, но не имеют типа элемента, начиная с имени продукта (т. Е. «03.64.0005_11_10»), который может иметь тысячи вариантов (проблема вторая).Как десериализовать этот JSON, чтобы заполнить правильные объекты?Я пробовал RestCharp, Json.net, но я всегда застреваю на свойстве products, которое не могу прочитать и заполнить динамически.

Я попробовал ответы ниже, но безуспешно:

Как десериализовать динамическое свойство json с помощью RestSharp в C #? Десериализовать JSON в динамический объект C #?

Не могли бы вы мне помочь, пожалуйста?

  "billingAddress": {
    "zip": "64001340",
    "state": "PI",
    "number": "3443",
    "status": "ACTIVE",
    "firstName": "Fulano",
    "telephone": {
      "type": "billing",
      "number": "88112244"
    },
    "neighbourhood": "Centro"
  },
  "clientId": "cliente3",
  "documents": [
    {
      "type": "cpf",
      "number": "12345678901"
    }
  ],
  "fulfillments": {
    "F1": {
      "id": "F1",
      "orderId": "4017116",
      "channelId": "channel2",
      "clientId": "cliente3",
      "locationId": "708",
      "shipment": {
        "method": "Economica",
        "carrierName": "Transportadora"
      },
      "status": "CANCELED",
      "type": "SHIPMENT",
      "enablePrePicking": false,
      "items": {
        "03.64.0005_11_10": {
          "sku": "03.64.0005_11_10",
          "quantity": 0,
          "stockType": "PHYSICAL",
          "orderedQuantity": 1,
          "returnedQuantity": 0,
          "canceledQuantity": 1,
          "itemType": "OTHER",
          "presale": false,
          "enablePicking": true
        },
        "18.06.0220_48_2": {
          "sku": "18.06.0220_48_2",
          "quantity": 0,
          "stockType": "PHYSICAL",
          "orderedQuantity": 1,
          "returnedQuantity": 0,
          "canceledQuantity": 1,
          "itemType": "OTHER",
          "presale": false,
          "enablePicking": true
        }
      }
    },
    "F2": {
      "id": "F2",
      "orderId": "4017116",
      "channelId": "channel2",
      "clientId": "cliente3",
      "locationId": "003",
      "operator": {
        "id": "5188",
        "name": "Loja da Vila"
      },
      "ownership": "oms",
      "shipment": {
        "method": "Economica",
        "carrierName": "Transportadora"
      },
      "status": "SHIPPING_READY",
      "type": "SHIPMENT",
      "enablePrePicking": true,
      "items": {
        "18.04.1465_01_3": {
          "sku": "18.04.1465_01_3",
          "quantity": 1,
          "stockType": "PHYSICAL",
          "orderedQuantity": 1,
          "returnedQuantity": 0,
          "canceledQuantity": 0,
          "itemType": "OTHER",
          "presale": false,
          "enablePicking": true
        },
        "18.16.0630_13_10": {
          "sku": "18.16.0630_13_10",
          "quantity": 1,
          "stockType": "PHYSICAL",
          "orderedQuantity": 1,
          "returnedQuantity": 0,
          "canceledQuantity": 0,
          "itemType": "OTHER",
          "presale": false,
          "enablePicking": true
        }
      }
    }
  },
  "createdAt": "2019-06-08T21:41:12.000Z",
  "updatedAt": "2019-06-08T21:41:12.000Z"
}

To

public class BillingAddress
{
    public string zip { get; set; }
    public string state { get; set; }
    public string number { get; set; }
    public string status { get; set; }
    public string firstName { get; set; }
    public Telephone telephone { get; set; }
    public string neighbourhood { get; set; }
}

public class Fulfillment
{
    public string id { get; set; }
    public string orderId { get; set; }
    public string channelId { get; set; }
    public string clientId { get; set; }
    public string locationId { get; set; }
    public Shipment shipment { get; set; }
    public string status { get; set; }
    public string type { get; set; }
    public bool enablePrePicking { get; set; }
    public List<Item> items { get; set; }
}

public class Item
{
    public string sku { get; set; }
    public int quantity { get; set; }
    public string stockType { get; set; }
    public int orderedQuantity { get; set; }
    public int returnedQuantity { get; set; }
    public int canceledQuantity { get; set; }
    public string itemType { get; set; }
    public bool presale { get; set; }
    public bool enablePicking { get; set; }
}

Ответы [ 3 ]

0 голосов
/ 19 июня 2019

Если проблема заключается только в том, что ключи являются динамическими, но структура этих объектов с динамическим ключом четко определена, тогда вы можете использовать Dictionary<string, T> (вместо List<T>) для обработки динамических ключей.Из вашего примера JSON это выглядит так.Таким образом, вам понадобится словарь для fulfillments на корневом уровне и items в fulfillments.Ваши классы должны выглядеть следующим образом:

public class RootObject
{
    public BillingAddress billingAddress { get; set; }
    public string clientId { get; set; }
    public List<Document> documents { get; set; }
    public Dictionary<string, Fulfillment> fulfillments { get; set; }
    public DateTime createdAt { get; set; }
    public DateTime updatedAt { get; set; }
}

public class BillingAddress
{
    public string zip { get; set; }
    public string state { get; set; }
    public string number { get; set; }
    public string status { get; set; }
    public string firstName { get; set; }
    public Telephone telephone { get; set; }
    public string neighbourhood { get; set; }
}

public class Telephone
{
    public string type { get; set; }
    public string number { get; set; }
}

public class Document
{
    public string type { get; set; }
    public string number { get; set; }
}

public class Fulfillment
{
    public string id { get; set; }
    public string orderId { get; set; }
    public string channelId { get; set; }
    public string clientId { get; set; }
    public string locationId { get; set; }
    public Operator @operator { get; set; }
    public string ownership { get; set; }
    public Shipment shipment { get; set; }
    public string status { get; set; }
    public string type { get; set; }
    public bool enablePrePicking { get; set; }
    public Dictionary<string, Item> items { get; set; }
}

public class Operator
{
    public string id { get; set; }
    public string name { get; set; }
}

public class Shipment
{
    public string method { get; set; }
    public string carrierName { get; set; }
}

public class Item
{
    public string sku { get; set; }
    public int quantity { get; set; }
    public string stockType { get; set; }
    public int orderedQuantity { get; set; }
    public int returnedQuantity { get; set; }
    public int canceledQuantity { get; set; }
    public string itemType { get; set; }
    public bool presale { get; set; }
    public bool enablePicking { get; set; }
}

Затем десериализовать JSON в класс RootObject:

var root = JsonConvert.DeserializeObject<RootObject>(json);

Вот рабочая демонстрация: https://dotnetfiddle.net/xReEQh

0 голосов
/ 19 июня 2019

Для сообщений JSON с динамическими ключами (т. Е. Переход от сообщения к сообщению) следует начинать с декодирования в динамические объекты C #. Одним декодированным (большинство синтаксических анализаторов JSON его поддерживают) вы перечисляете каждое динамическое свойство, а затем конвертируете его значение в POCO, например Fulfillment, Item и т. Д. (Или просто продолжаете работать с динамическим объектом).

Вот пример, который работает с вашим JSON https://dotnetfiddle.net/U5NfzC

0 голосов
/ 19 июня 2019

Да, эта структура действительно не предназначена для такой работы с JSON.Похоже, что свойство выполнения должно быть массивом этих объектов вместо того, чтобы иметь эти пронумерованные свойства.Похоже, это автоматически генерируется из файла EDI или чего-то еще, даже при том, что большинство хороших инструментов преобразования достаточно умны, чтобы этого не делать.

Вариант A: Посмотрите, генерирует ли этот файл тот, кто его генерируетпотому что вы можете исправить их процесс.

Вариант B: Если это невозможно, сделайте свойством выполнений тип словаря, в котором класс выполнения соответствует вашему внутреннему объекту выполнения.Это затем десериализовало бы его «должным образом» и дало бы вам словарь, на который вы можете ссылаться с помощью клавиши «F1» до «FN», но в идеале вы должны создать список или массив из своего словаря при его использовании.Даже если заказ имеет значение, у вас всегда есть поле id для сортировки позже.

// Property on you deserialization object
public Dictionary<string, Fullfillment> fulfillmentDictionary {get; set;}

// Creating the list for easier use of the data
List<Fullfillment> fulfillments = fulfillmentDictionary.Values.ToList();

Аналогичная логика будет применяться к спискам ваших товаров.

...