How to deserialize this JSON with VB.NET

对着背影说爱祢 提交于 2019-12-11 06:05:51

问题


I have this JSON data:

{"asks":[["0.26039995",19.91610429],["0.26063345",3070.562292]],"bids":[["0.26000017",30381.45513902],["0.26000000",8299.1410574]],"isFrozen":"0","seq":50663190}

I wrote this code:

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    Dim wc As New WebClient
    Dim sURL As String = "https://poloniex.com/public?command=returnOrderBook&currencyPair=USDT_STR&depth=" & 2
    Dim res As String = wc.DownloadString(New Uri(sURL))

    Dim m As IEnumerable(Of Rootobject) = JsonConvert.DeserializeObject(Of IEnumerable(Of Rootobject))(res)
End Sub


Public Class Rootobject
    Public Property asks As asksDef()
    Public Property bids As bidsDef()
    Public Property isFrozen As String
    Public Property seq As Integer
End Class

Public Class asksDef
    Public Property priceAsk As String
    Public Property quantAsk As Integer
End Class

Public Class bidsDef
    Public Property priceBid As String
    Public Property quantBid As Integer
End Class

I've pasted the JSON class with VB paste special. The question is: how to access to every ask, every bid and the isFrozen and seq values.

I got an error on this line:

Dim m As IEnumerable(Of Rootobject) = JsonConvert.DeserializeObject(Of IEnumerable(Of Rootobject))(res)

The error message I got is:

An unhandled exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll

Additional information: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.IEnumerable`1[poloniexAPI.Rootobject]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.

To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.

Path 'asks', line 1, position 8.

I'm stuck again this time with this JSON model. How to proceed with this?

{"BTC_BCN":{"id":7,"last":"0.00000042","lowestAsk":"0.00000043","highestBid":"0.00000042","percentChange":"0.00000000","baseVolume":"179.56364789","quoteVolume":"436786711.33832335","isFrozen":"0","high24hr":"0.00000043","low24hr":"0.00000039"},"BTC_BELA":{"id":8,"last":"0.00002091","lowestAsk":"0.00002097","highestBid":"0.00002091","percentChange":"-0.10831556","baseVolume":"12.57891843","quoteVolume":"579476.06165462","isFrozen":"0","high24hr":"0.00002345","low24hr":"0.00002088"}}


回答1:


The root cause of this specific error is that your JSON represents a single object (which contains some arrays and other info) but you are trying to deserialize it as if the whole thing were enumerable. However, fixing this will not solve the whole problem; there are a couple of other issues as well.

This JSON is a little odd because it uses an array to group together each price and quantity pair for the bids and asks, whereas an object seems like it would be more appropriate (and more easily consumable). Since Json.Net does not have a facility to automatically map an array into class properties by index, you will need to use a custom JsonConverter to deserialize this data properly. Also, the prices are represented as strings for some reason where they should be decimals like the quantity. This can be handled in the converter as well.

Before we get to the converter, let's fix your class definitions. Since the bids and asks use the same structure, I would recommend defining a common class for that. Both price and quantity properties should be declared as Decimal:

Public Class PriceQuantityPair
    Public Property price As Decimal
    Public Property quantity As Decimal
End Class

Then define your root class like this:

Class RootObject
    Public Property asks As List(Of PriceQuantityPair)
    Public Property bids As List(Of PriceQuantityPair)
    Public Property isFrozen As String
    Public Property seq As Integer
End Class

Here is the code for the converter, which will translate the array structure for each pair into a PriceQuantityPair instance:

Class PriceQuantityPairConverter
    Inherits JsonConverter

    Public Overrides Function CanConvert(objectType As Type) As Boolean
        Return objectType Is GetType(PriceQuantityPair)
    End Function

    Public Overrides Function ReadJson(reader As JsonReader, objectType As Type, existingValue As Object, serializer As JsonSerializer) As Object
        Dim ja As JArray = JArray.Load(reader)
        Dim pair As PriceQuantityPair = New PriceQuantityPair()
        pair.price = ja(0).ToObject(Of Decimal)()
        pair.quantity = ja(1).ToObject(Of Decimal)()
        Return pair
    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

To use the converter, add a <JsonConverter> attribute to the PriceQuantityPair class like this:

<JsonConverter(GetType(PriceQuantityPairConverter))>
Public Class PriceQuantityPair
    ...
End Class

Finally, deserialize the JSON into the RootObject class like this:

Dim root As RootObject = JsonConvert.DeserializeObject(Of RootObject)(json)

Here is a demo: https://dotnetfiddle.net/dDHLtR




回答2:


As far as I understand your question. You can access the properties with the 'm' variable where you are storing the de serialized data. Ex: m.isFrozen, m.seq, m.bids() & m.asks().



来源:https://stackoverflow.com/questions/47873706/how-to-deserialize-this-json-with-vb-net

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!