json - 使用 Newtonsoft 反序列化 JSON 属性(当它可以是单个字符串或 JARRAY 时)

标签 json vb.net json.net

我正在从 Web 服务器检索 JSON 响应,并为所有属性创建了强类型类,没有任何问题,除了一个可以是单个字符串值或嵌套数组的属性之外。

JSON 示例:

"meta_data": [
{
  "id": 12772,
  "key": "_shipping_phone",
  "value": ""
},
{
  "id": 12786,
  "key": "status",
  "value": "completed"
},
{
  "id": 12788,
  "key": "Payment type",
  "value": "instant"
},
{
  "id": 12796,
  "key": "_transaction_fee",
  "value": "0.39"
},
{
  "id": 12806,
  "key": "connect_destination_normalized",
  "value": "1"
},
{
  "id": 12807,
  "key": "wc_connect_labels",
  "value": [
    {
      "label_id": 1633947,
      "tracking": "9400***************",
      "refundable_amount": 3.930000000000000159872115546022541821002960205078125,
      "created": 1589499950667,
      "carrier_id": "usps",
      "service_name": "USPS - First Class Mail",
      "status": "PURCHASED",
      "package_name": "Bubble Mailer",
      "product_names": [
        "Peace Love And Wine Sub Tshirt"
      ],
      "receipt_item_id": 60476008,
      "created_date": 1589499955000,
      "main_receipt_id": 46201718,
      "rate": 3.930000000000000159872115546022541821002960205078125,
      "currency": "USD",
      "expiry_date": 1605051955000,
      "label_cached": 1589499962000
    },
    {
      "label_id": 1633942,
      "tracking": null,
      "refundable_amount": 0,
      "created": 1589499912741,
      "carrier_id": null,
      "service_name": "USPS - First Class Mail",
      "status": "PURCHASE_ERROR",
      "package_name": "Bubble Mailer",
      "product_names": [
        "Peace Love And Wine Sub Tshirt"
      ],
      "receipt_item_id": -1,
      "created_date": 1589499912000,
      "error": "The transaction was declined."
    },
    {
      "label_id": 1633913,
      "tracking": null,
      "refundable_amount": 0,
      "created": 1589499712367,
      "carrier_id": null,
      "service_name": "USPS - First Class Mail",
      "status": "PURCHASE_ERROR",
      "package_name": "Bubble Mailer",
      "product_names": [
        "Peace Love And Wine Sub Tshirt"
      ],
      "receipt_item_id": -1,
      "created_date": 1589499712000,
      "error": "The transaction was declined."
    }
  ]
}

如您所见,value 键是一个普通的字符串值(或空白字符串)。然而,正如最终条目所示,它还可以更多。

这是我的强类型类:

Public Class Meta_Data
    Public Property id As Integer
    Public Property key As String
    '<JsonConverter(GetType(SingleOrArrayConverter(Of Values())))>
    Public Property value As Values()
End Class

Public Class Values
    Public Property label_id As Integer
    Public Property tracking As String
    Public Property refundable_amount As String
    Public Property created As String
    Public Property carrier_id As String
    Public Property service_name As String
    Public Property status As String
    Public Property package_name As String
    Public Property product_names As String()
    Public Property receipt_item_id As String
    Public Property created_date As String
    Public Property [error] As String
    Public Property main_receipt_id As String
    Public Property rate As String
    Public Property currency As String
    Public Property expiry_date As String
    Public Property label_cached As String
End Class

我在互联网上搜索了解决方案,但未能找到一个。我尝试了找到的不同转换器示例,但没有一个起作用,因为它们仍然尝试通过 Values 类传递单个字符串。

这是我的反序列化调用:

Dim info As Order = JsonConvert.DeserializeObject(Of Order)(responseFromServer)

我还有多个其他类,我不打算占用空间来显示它们,但根类称为 Order。 基本上,有没有办法在处理反序列化时检查 value 以查看它是否是字符串并阻止它通过 Values 类进行处理?

最佳答案

由于您希望以不同于数组的方式处理单个字符串值,因此您需要更改模型以使其具有多态性。也就是说,创建一个基类,其中包含所有 meta_data 项共有的 idkey 属性,然后创建子类来表示字符串和数组变种。所以,像这样:

Public Class Order
    Public Property meta_data As List(Of BaseMetaData)
End Class

<JsonConverter(GetType(MetaDataConverter))>
Public Class BaseMetaData
    Public Property id As Integer
    Public Property key As String
End Class

Public Class StringMetaData
    Inherits BaseMetaData
    Public Property value As String
End Class

Public Class ComplexMetaData
    Inherits BaseMetaData
    Public Property value As List(Of Values)
End Class

Public Class Values
    Public Property label_id As Integer
    Public Property tracking As String
    Public Property refundable_amount As String
    Public Property created As String
    Public Property carrier_id As String
    Public Property service_name As String
    Public Property status As String
    Public Property package_name As String
    Public Property product_names As String()
    Public Property receipt_item_id As String
    Public Property created_date As String
    Public Property [error] As String
    Public Property main_receipt_id As String
    Public Property rate As String
    Public Property currency As String
    Public Property expiry_date As String
    Public Property label_cached As String
End Class

然后您可以为基类创建一个自定义 JsonConverter 来检测值类型并创建正确的子类:

Public Class MetaDataConverter
    Inherits JsonConverter

    Public Overrides Function CanConvert(objectType As Type) As Boolean
        Return GetType(BaseMetaData).IsAssignableFrom(objectType)
    End Function

    Public Overrides Function ReadJson(reader As JsonReader, objectType As Type, existingValue As Object, serializer As JsonSerializer) As Object
        Dim jo As JObject = JObject.Load(reader)
        Dim val As JToken = jo("value")
        Dim meta As BaseMetaData
        If val.Type = JTokenType.Array Then
            meta = New ComplexMetaData()
        Else
            meta = New StringMetaData()
        End If
        serializer.Populate(jo.CreateReader(), meta)
        Return meta
    End Function

    Public Overrides ReadOnly Property CanWrite As Boolean
        Get
            Return False
        End Get
    End Property

    Public Overrides Sub WriteJson(writer As JsonWriter, value As Object, serializer As JsonSerializer)
        Throw New NotImplementedException()
    End Sub
End Class

最后一部分是使用 JsonConverter 属性标记 BaseMetaData,我已经在上面的模型声明中完成了该操作。然后,您可以像平常一样反序列化,一切都应该“正常工作”。

这是一个工作演示:https://dotnetfiddle.net/3uYXKu

关于json - 使用 Newtonsoft 反序列化 JSON 属性(当它可以是单个字符串或 JARRAY 时),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61905410/

相关文章:

sql - 更新数据库失败,因为数据库是只读的

c# - JArray 阻止日期解析

json.net - ASP.NET Web API 自定义 DateTime 示例值格式

c# - 新的 DLL hell ;绑定(bind)了错误的程序集版本

javascript - 如何在jQuery上修改JSON字符串化表单信息

json - 如何使用 Jackson 将 Scala 值类序列化为字符串?

python - Django 。如何在html <tr><td>name</td><td>value</td><td>date</td></tr>标签中显示json文件?

mysql - 如何在具有多个条件的mysql数据库中选择多个值

mysql - 如何在我的表单 Vb Net 中没有事件的情况下从数据库 MySQL 获取值

php - 如何使用php中的str_replace函数替换数组中的值