如何在 vb.net 中使用动态修复命名元素反序列化 Json?

How to deserialize Json with fix named elements dynamically in vb.net?

我正在 vb.net 应用程序(使用 httpclient)中实现 Ameritrade Rest API 的接口。
除其他事项外,我还必须从股票代码列表中查询报价(例如 AMD、MSFT、AMZN 等)。
API 的调用没有问题,我得到了有效的 Json 返回,但是 Json 没有以某种方式返回,我希望如此。
我现在正在寻找处理该问题的最佳方法...

这不是 Rest 的第一个接口 API,我已经实现了。
通常,我在vb.net中实现一个相应的数据class,然后使用JsonConvert(来自Newtonsoft)反序列化Json字符串进入我的数据 class.
示例:

 Dim oObject As New DataClass
 oObject = JsonConvert.DeserializeObject(Of DataClass)(JsonString)

其中DataClass是根据Json字符串中的数据定义的vb.netclass

问题:
要查询的股票代码列表是 dynamic 并且可以从 api call 更改为 api call.
如果我 - 例如- 在通话中查询 AMD 和 MSFT,我返回(只截取几个字段)以下 Json:

{
  "AMD": {
    "assetType": "EQUITY",
    "symbol": "AMD",
    "description": "Advanced Micro Devices, Inc. - Common Stock",
    "bidPrice": 92.11
  },
  "MSFT": {
    "assetType": "EQUITY",
    "symbol": "MSFT",
    "description": "Microsoft Corporation - Common Stock",
    "bidPrice": 243.1
  }
}

为了能够反序列化 Json,我必须实现以下数据类:

Public Class DataClass
  Public Property AMD As AMD
  Public Property MSFT As MSFT
End Class

Public Class AMD
  Public Property assetType As String
  Public Property symbol As String
  Public Property description As String
  Public Property bidPrice As Double
End Class

Public Class MSFT
  Public Property assetType As String
  Public Property symbol As String
  Public Property description As String
  Public Property bidPrice As Double
End Class

这可行,但绝对是静态的,没有任何意义,因为我必须为任何代码实施a(相同)class,我也许想在功能里查询。

我希望得到一个动态列表,以便我可以按如下方式实现 class:

Public Class DataClass
  Public Property TickerDetails As List(Of TickerDetail)
End Class

Public Class TickerDetail
  Public Property assetType As String
  Public Property symbol As String
  Public Property description As String
  Public Property bidPrice As Double
End Class

这样,我就可以在 TickerDetails 列表中反序列化并遍历列表(无论我查询了哪些符号)。
但是,我无法改变,我通过 API...

得到的东西

问题:
处理这个问题的最佳方法是什么?

您应该创建一个 class 来表示通用股票,然后使用 DeserializeObject 将其反序列化为 Dictionary(Of String, [classname]) ,其中 Key 表示股票代码值代表 class.

看看这个例子:

Public Class Stock
  Public Property assetType As String
  Public Property symbol As String
  Public Property description As String
  Public Property bidPrice As Double
End Class
'...
Dim stocks = JsonConvert.DeserializeObject(Of Dictionary(Of String, Stock))(response)

示例:Live Demo

首先感谢您的评论。 我现在完全不同了...
我在使用 Ameritrade 时遇到了更多问题 API:

  • 一些字段以前导数字命名(52WkHigh 和 52WkLow)和 vb.net 开发人员知道,VB.net 不喜欢 class 中的属性 以前导数字命名
  • 所以我不得不“修补”接收到的 Json 数据,并即时将名称更改为其他名称(“52WkHigh”更改为“dble52WkHigh”,“52WkLow”更改为“dble52WkLow”)以便能够反序列化
    关于数据class,有什么不好

此外,我终于需要(尽可能快地)数据 table 并且“还有很长的路要走”:
获取数据 -> 反序列化到数据 class -> 遍历数据 class 并超越数据 table.
中的数据 所以..我的新解决方案(使用 JObject):
注:需求:

Imports Newtonsoft.Json.Linq

代码片段:

在内存中创建数据table:

  Dim dtErgebnis As New DataTable
  Dim drTemp As DataRow
  With dtErgebnis.Columns
    .Add("symbol", System.Type.GetType("System.String"))
    .Add("lastPrice", System.Type.GetType("System.Double"))
    .Add("lastSize", System.Type.GetType("System.Int32"))
    .Add("quoteTime", System.Type.GetType("System.DateTime")) ' Note: is a Long in Json
    ...
 End With

解析Json-字符串并填充数据table:
通过 httpclient 获取数据(在 JsonString 中)...

Dim oJson As JObject = JObject.Parse(JsonString) ' creates children tokens
Dim results As List(Of JToken) = oJson.Children().ToList
 For Each item As JProperty In results
    item.CreateReader()
    drTemp = dtErgebnis.NewRow() ' create a new row to data table in memory
    ' Fill the fields
    drTemp("symbol") = item.Value("symbol")
    drTemp("lastPrice") = item.Value("lastPrice")
    drTemp("lastSize") = item.Value("lastSize")
    drTemp("quoteTime") = GetUTCDateFromTimeStamp(item.Value("quoteTimeInLong")).AddHours(1) ' original Long 
...
'  Add the new row to the  data table
   dtErgebnis.Rows.Add(drTemp)
   ' Save the changes
    dtErgebnis.AcceptChanges()
Next

补充说明:Ameritrade API 返回时间戳一样长(额外的障碍),但我(我也认为你;-)希望它作为日期时间。 因此 Long(我认为这种数据类型来自 Java/Unix)必须“翻译”为 datetime = vb.net 下面的函数 GetUTCDateFromTimeStamp:

  Public Function GetUTCDateFromTimeStamp(TimeStamp As Long) As DateTime
    Static startTime As New DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)
    Return startTime.AddMilliseconds(TimeStamp)
  End Function

补充说明:
因为我想要瑞士时间,所以我在 UTC 时间上加了一小时。

所以..这对我来说是一个很好的解决方案(完全适用于 Ameritrade API)。 而且..速度非常快...(我得到了所有字段的 19 个代码,并在数据网格中显示结果(数据 table))。
总共用时 < 1 秒(“感觉”大约 500 毫秒)

希望这对某人有所帮助...