Weird behavior during parsing Json

Mattia Fanti 356 Reputation points
2022-02-18T00:32:35.28+00:00

I'm parsing this JSON

{"error":null,"result":{"KIBAUSDT":{"limit":100,"offset":0,"total":2,"records":[{"user":2996434,"id":82873069172,"market":"KIBAUSDT","freeze":"100","fee_stock":"","source":"web","type":1,"side":1,"ctime":1645133452.181028,"mtime":1645133452.181028,"price":"0.00002","amount":"100","taker_fee":"0.0035","maker_fee":"-0.003","left":"100","deal_stock":"0","deal_money":"0","deal_fee":"0","alt_fee":"0","deal_fee_alt":"0","status":0},{"user":2996434,"id":82873306723,"market":"KIBAUSDT","freeze":"100","fee_stock":"","source":"web","type":1,"side":1,"ctime":1645133526.563619,"mtime":1645133546.966621,"price":"0.00001124","amount":"200","taker_fee":"0.0035","maker_fee":"-0.003","left":"100","deal_stock":"100","deal_money":"0.001124","deal_fee":"-0.000003372","alt_fee":"0","deal_fee_alt":"0","status":1}]}},"id":300991746}

which is basically the API of one crypto exchange that is showing the orders that I've opened. I'm using quicktype.io to create the code of a new class file

Imports System
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Converters
Imports System.Runtime.CompilerServices

Namespace OrdiniAperti
    Partial Public Class Openorders
        <JsonProperty("error")>
        Public Property [Error] As Object
        <JsonProperty("result")>
        Public Property Result As Result
        <JsonProperty("id")>
        Public Property Id As Long
    End Class

    Partial Public Class Result
        <JsonProperty("KIBAUSDT")>
        Public Property Kibausdt As Kibausdt
    End Class

    Partial Public Class Kibausdt
        <JsonProperty("limit")>
        Public Property Limit As Long
        <JsonProperty("offset")>
        Public Property Offset As Long
        <JsonProperty("total")>
        Public Property Total As Long
        <JsonProperty("records")>
        Public Property Records As Record()
    End Class

    Partial Public Class Record
        <JsonProperty("user")>
        Public Property User As Long
        <JsonProperty("id")>
        Public Property Id As Long
        <JsonProperty("market")>
        Public Property Market As String
        <JsonProperty("freeze")>
        Public Property Freeze As String
        <JsonProperty("fee_stock")>
        Public Property FeeStock As String
        <JsonProperty("source")>
        Public Property Source As String
        <JsonProperty("type")>
        Public Property Type As Long
        <JsonProperty("side")>
        Public Property Side As Long
        <JsonProperty("ctime")>
        Public Property Ctime As Double
        <JsonProperty("mtime")>
        Public Property Mtime As Double
        <JsonProperty("price")>
        Public Property Price As String
        <JsonProperty("amount")>
        <JsonConverter(GetType(ParseStringConverter))>
        Public Property Amount As Long
        <JsonProperty("taker_fee")>
        Public Property TakerFee As String
        <JsonProperty("maker_fee")>
        Public Property MakerFee As String
        <JsonProperty("left")>
        <JsonConverter(GetType(ParseStringConverter))>
        Public Property Left As Long
        <JsonProperty("deal_stock")>
        <JsonConverter(GetType(ParseStringConverter))>
        Public Property DealStock As Long
        <JsonProperty("deal_money")>
        <JsonConverter(GetType(ParseStringConverter))>
        Public Property DealMoney As Long
        <JsonProperty("deal_fee")>
        <JsonConverter(GetType(ParseStringConverter))>
        Public Property DealFee As Long
        <JsonProperty("alt_fee")>
        <JsonConverter(GetType(ParseStringConverter))>
        Public Property AltFee As Long
        <JsonProperty("deal_fee_alt")>
        <JsonConverter(GetType(ParseStringConverter))>
        Public Property DealFeeAlt As Long
        <JsonProperty("status")>
        Public Property Status As Long
    End Class

    Partial Public Class Openorders
        Public Shared Function FromJson(ByVal json As String) As Openorders
            Return JsonConvert.DeserializeObject(Of Openorders)(json, Settings)
        End Function
    End Class

    Public Module Serialize
        <Extension()>
        Public Function ToJson(ByVal self As Openorders) As String
            Return JsonConvert.SerializeObject(self, Settings)
        End Function
    End Module

    Friend Module Converter
        Public ReadOnly Settings As JsonSerializerSettings = New JsonSerializerSettings With {
            .MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
            .DateParseHandling = DateParseHandling.None
        }
    End Module

    Friend Class ParseStringConverter
        Inherits JsonConverter

        Public Overrides Function CanConvert(ByVal t As Type) As Boolean
            Return t Is GetType(Long) OrElse t Is GetType(Long?)
        End Function

        Public Overrides Function ReadJson(ByVal reader As JsonReader, ByVal t As Type, ByVal existingValue As Object, ByVal serializer As JsonSerializer) As Object
            If reader.TokenType = JsonToken.Null Then Return Nothing
            Dim value = serializer.Deserialize(Of String)(reader)
            Dim l As Long

            If Long.TryParse(value, l) Then
                Return l
            End If

            Throw New Exception("Cannot unmarshal type long")
        End Function

        Public Overrides Sub WriteJson(ByVal writer As JsonWriter, ByVal untypedValue As Object, ByVal serializer As JsonSerializer)
            If untypedValue Is Nothing Then
                serializer.Serialize(writer, Nothing)
                Return
            End If

            Dim value = CLng(untypedValue)
            serializer.Serialize(writer, value.ToString())
            Return
        End Sub

        Public Shared ReadOnly Singleton As ParseStringConverter = New ParseStringConverter()
    End Class
End Namespace

and then I'm using the following code in order to parse some of the property I need:

 Dim json = Await wc1.DownloadStringTaskAsync("https://api.hotbit.io/api/v1/order.pending?market=KIBA/USDT&offset=0&limit=100&api_key=44812d8f-66d3-01c0-94c3b29305040b03&sign=F3330B924E1873B9C8FAB40A25D7B851")
                'deserialize the json
                Dim rootObj = Openorders.FromJson(json)
                'navigate to Kibausdt
                Dim kibausdt = rootObj.Result.Kibausdt

                'check total
                If kibausdt.Total = 0 Then
                    RichTextBox1.Text = "0 opened orders"

                Else
                    RichTextBox1.Clear()
                    'loop through records
                    For Each record In kibausdt.Records
                        Dim side As String = record.Side.ToString()
                        Dim amount As Long = record.Amount
                        Dim price As String = record.Price.ToString
                        Dim filled As Long = record.Left
                        Dim status As String = record.Status.ToString
                        If side = "1" Then
                            side = "SELL"
                        Else
                            side = ("BUY ")
                        End If
                        If status = "1" Then
                            status = "Hidden order"
                        Else
                            status = "Not hidden order"
                        End If
                        Dim percentage As Double = ((filled * 100) / amount)
                        RichTextBox1.Text &= "    " & side & " - " & "      " & amount & " - " & "            " & price.ToString & " - " & "    " & percentage.tostring & " % " & " - " & "    " & status & vbCr
                    Next
                End If

As you can see the API lack of filled % property, so I'm calculating it with the formula ((filled * 100)/ whole order amount). The code is working when I have 0 order opened and when an order ( or more) is opened but still not filled, so with 0% filled. The problem starts when the order is starting to be filled, so the % increase. As soon as the % moves from 0 I'm getting the error on the class file at the line Throw New Exception("Cannot unmarshal type long")

System.Exception: 'Cannot unmarshal type long'

So I've been looking at the class file code and sow that "left" and "amount" properties are declared as Long. So I've tried to declare them as Double and even as Decimal, So I changed also Dim filled As Long to Dim filled As Double as well as Dim amount as long to Dim amount as Double into the main form. But now, I'm getting the following error on the line Return JsonConvert.DeserializeObject(Of Openorders)(json, Settings) of the Class File:

Newtonsoft.Json.JsonSerializationException: 'Error setting value to 'Left' on 'HotBit_APIs.OrdiniAperti.Record

How is this behavior possible? What Am I doing wrong? Thanks

VB
VB
An object-oriented programming language developed by Microsoft that is implemented on the .NET Framework. Previously known as Visual Basic .NET.
2,564 questions
.NET Runtime
.NET Runtime
.NET: Microsoft Technologies based on the .NET software framework.Runtime: An environment required to run apps that aren't compiled to machine language.
1,117 questions
{count} votes

2 answers

Sort by: Most helpful
  1. Jiachen Li-MSFT 26,426 Reputation points Microsoft Vendor
    2022-02-18T05:43:43.673+00:00

    Hi @Mattia Fanti ,
    I used the code you provided and got the exception Error setting value to 'DealMoney' on 'Deserialize_a_dictionary_json.Record'.
    When I changed all long types to Decimal types, there were no exceptions.
    And I got the following result.
    175648-image.png
    Maybe you can try to change all long types to Decimal types.
    Best Regards.
    Jiachen Li

    ----------

    If the answer is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


  2. Mattia Fanti 356 Reputation points
    2022-02-18T14:28:05.657+00:00

    I solved changing all "long" types to "Double"

    0 comments No comments