如何反序列化动态json属性以对象?

时间:2019-06-19 00:24:39

标签: c# json json.net restsharp

我正在尝试将动态JSON(从API)反序列化为正确的对象,但是某些项目没有类型。在示例JSON中,“ fulfillment”属性具有值“ F1”和“ F2”,并且可能具有更多值(问题1)。其中,项目属性具有产品订购信息,但没有以产品名称(即“ 03.64.0005_11_10”)开头的项目类型,该名称可以是成千上万个选项(问题二)。 如何反序列化此JSON以填充正确的对象?我尝试了Json.net的RestCharp,但是我总是卡在无法动态读取和填充的产品属性上。

我尝试了以下答案,但没有成功:

How I deserialize a dynamic json property with RestSharp in C#? Deserialize JSON into C# dynamic object?

你能帮我吗?

  "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 :(得分:0)

是的,这种结构实际上并不意味着可以与JSON一起使用。看起来完成属性应该是这些对象的数组,而不是具有编号的属性。看起来好像是从EDI文件等自动生成的,即使大多数好的转换工具都足够聪明,无法做到这一点。

选项A:查看是否有人为您生成文件可以纠正他们的过程。

选项B:如果不可能,则将您的实现属性设为Dictionary类型,其中,实现是该内部实现对象具有的类。然后,它将“适当地”反序列化它,并为您提供一个字典,您可以使用“ 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();

类似的逻辑将应用于您的商品列表。

答案 1 :(得分:0)

如果问题仅在于键是动态的,而这些动态键对象的结构是明确定义的,则可以使用Dictionary<string, T>(而不是List<T>)来处理动态键。从示例JSON来看,情况就是这样。因此,您需要在根级别为fulfillmentsitems中的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

答案 2 :(得分:0)

对于具有动态键(即从一个消息更改为另一个消息)的JSON消息,您应该先将其解码为动态C#对象。一个经过解码(大多数JSON解析器都支持它)的用户会枚举每个动态属性,然后将其值转换为POCO,例如Fulfillment,Item等(或继续使用动态对象)。

以下是与您的JSON https://dotnetfiddle.net/U5NfzC一起使用的示例