How to parse Poloniex Json into VB Net Object? - json

I'm currently pulling in the Poloniex returnCompleteBalances info in the following JSON format:
{"LTC":{"available":"5.015","onOrders":"1.0025","btcValue":"0.078"},"NXT:{...} ... }
I am trying to add the info to a class I made, and separate the different coins(property names) and their associated info. So far I have the following:
Sub GetBalances()
Dim method As String = calldata("returnCompleteBalances")
Dim allData As JObject = JObject.Parse(method)
Dim coinlist As New List(Of balancedata)
For Each token As JToken In allData("objects")
Dim prop As JProperty = token
coinlist.Add(New balancedata With {.Coin = prop.Name, .available = prop.Value("available"), .onOrders = prop.Value("onOrders"), .btcValue = prop.Value("btcValue")})
Next
End Sub
And the class
Public Class balancedata
Public Property Coin As String
Public Property available As Decimal
Public Property onOrders As Decimal
Public Property btcValue As Decimal
End Class
When I run the code, I receive an error on the for each token as Jtoken line that reads: "Object reference not set to an instance of an object"
How do I resolve this? I do not know all of the values for the property name, LTC, BTC, etc. so I am trying to look through them all and itemize the associated values into a list.

Related

Deserializing JSON into a List (or other object type)

I am having issues deserializing some JSON into an object type that I can work with.
I have been playing around with multiple different ways to deserialize something, but I cannot get any of them to work. I am trying, currently, to use the Newtonsoft.Json deserializer.
Public Class ServerRecord
Inherits Record
<Newtonsoft.Json.JsonProperty("sys_class_name")>
Public Property sys_class_name As String
Get
End Get
Set(value As String)
End Set
End Property
<Newtonsoft.Json.JsonProperty("host_name")>
Public Property host_name As String
Get
End Get
Set(value As String)
End Set
End Property
<Newtonsoft.Json.JsonProperty("u_recovery_time_achievable")>
Public Property u_recovery_time_achievable As String
Get
End Get
Set(value As String)
End Set
End Property
End Class
Dim lstSNServersList As New List(Of ServerRecord)
Dim objServiceNowTableAPIClient As TableAPI.TableAPIClient(Of ServerRecord)
Dim objServiceNowRESTQueryResponse As RESTQueryResponse(Of ServerRecord)
objServiceNowTableAPIClient = New TableAPIClient(Of wServerRecord)(strServiceNowCMDBServersTableName, strServiceNowInstanceName, strServiceNowUser, strServiceNowPassword)
strServiceNowQuery = "sys_class_name=cmdb_ci_win_server^ORsys_class_name=cmdb_ci_linux_server"
objServiceNowRESTQueryResponse = objServiceNowTableAPIClient.GetByQuery(strServiceNowQuery)
'this much does work and it does return a result set
'this is my attempt to convert this response into a list of ServerRecords, but this does not work currently:
lstSNServersList = JsonConvert.DeserializeObject(Of List(Of ServerRecord))(objServiceNowRESTQueryResponse.RawJSON)
The objServiceNowRestQueryResponse.RawJSON string looks like this (though much longer):
{
"result":[
{
"sys_id":"00040665dbxxxxxx96191e",
"u_recovery_time_achievable":"720",
"sys_class_name":"cmdb_ci_linux_server",
"host_name":"rlserver001"
},
{
"sys_id":"00ec543d1xxxx66e4bcb6d",
"u_recovery_time_achievable":"4",
"sys_class_name":"cmdb_ci_linux_server",
"host_name":"plserver001"
},
{
"sys_id":"0105d975dbxxxxx8961998",
"u_recovery_time_achievable":"",
"sys_class_name":"cmdb_ci_linux_server",
"host_name":"tlserver001"
}
]
}
This is the error message I get when trying to run my code:
Exception thrown: 'Newtonsoft.Json.JsonSerializationException' in
Newtonsoft.Json.dll
Additional information: Cannot deserialize the current JSON object
(e.g. {"name":"value"}) into type
'System.Collections.Generic.List`1[CMDBReconciliation.CMDBReconciliation+ServiceNowServerRecord]'
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 'result', line 1, position 10.
This will work. It just extracts the array part from the json string.
Dim start As Integer = objServiceNowRESTQueryResponse.IndexOf("[")
Dim last As Integer = objServiceNowRESTQueryResponse.LastIndexOf("]")
lstSNServersList = JsonConvert.DeserializeObject(Of List(Of ServerRecord))(objServiceNowRESTQueryResponse.Substring(start, last - start + 1))

JSON deserialization error with Azure translation services

I am building a program in Visual Studio 2017 in Windows Forms - sorry but that's the only thing I know how to use - anyway, most everything for this is C#, so I've been having trouble getting help.
I have translated the Microsoft provided example for a C# program to connect to Azure Cognitive Translation services, signed up, got all my keys, etc.
When I run the code, I get the following error:
Newtonsoft.Json.JsonSerializationException:
'Cannot deserialize the
current JSON object (e.g. {"name":"value"}) into type
System.Collections.Generic.List1[System.Collections.Generic.Dictionary2[System.String,System.Collections.Generic.List1[System.Collections.Generic.Dictionary2[System.String,System.String]]]]'
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 'error', line 1, position 9.'
I have tried too many things to list from many different sources. I do not know a whole lot about JSON and am asking for help with the code to solve the above issue.
Public Class DetectedLanguage
Public Property language As String
Public Property score As Double
End Class
Public Class Translation
Public Property text As String
Public Property two As String
End Class
Public Class Example
Public Property detectedLanguage As DetectedLanguage
Public Property translations As Translation()
End Class
Dim textToTranslate As String = root
Dim fromLanguage As String
Dim fromLanguageCode As String = cabbr
Dim toLanguageCode As String = "en"
Dim endpoint As String = String.Format(TEXT_TRANSLATION_API_ENDPOINT, "translate")
Dim uri As String = String.Format(endpoint & "&from={0}&to={1}", fromLanguageCode, toLanguageCode)
Dim body As System.Object() = New System.Object() {New With {Key .Text = textToTranslate}}
Dim requestBody = JsonConvert.SerializeObject(body)
Using client = New HttpClient()
Using request = New HttpRequestMessage()
request.Method = HttpMethod.Post
request.RequestUri = New Uri(uri)
request.Content = New StringContent(requestBody, Encoding.UTF8, "application/json")
request.Headers.Add("Ocp-Apim-Subscription-Key", COGNITIVE_SERVICES_KEY)
request.Headers.Add("Ocp-Apim-Subscription-Region", "westus")
request.Headers.Add("X-ClientTraceId", Guid.NewGuid().ToString())
Dim response = client.SendAsync(request).Result
Dim responseBody = response.Content.ReadAsStringAsync().Result
Dim result = JsonConvert.DeserializeObject(Of List(Of Dictionary(Of String, List(Of Dictionary(Of String, String)))))(responseBody)
Dim translation = result(0)("translations")(0)("text")
rtRoot.Text = translation
End Using
End Using
I have already used the jsonutil site to paste my JSON code in and get the classes.
Here is my JSON content:
[
{
"detectedLanguage":{
"language":"nl",
"score":1.0
},
"translations":[
{
"text":"bord vervangen en uitvoerig getest",
"to":"nl"
},
{
"text":"Board replaced and tested extensively",
"to":"en"
}
]
}
]
OK!!! after playing around with this - Jimi - your solution worked!!! thank you SO much! i had to remove the following to lines: request.Headers.Add("Ocp-Apim-Subscription-Region", "westus") request.Headers.Add("X-ClientTraceId", Guid.NewGuid().ToString())

How to deserialize this JSON with VB.NET

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"}}
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
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().

Parsing JSON Objects within JSON arrays within JSON Objects in VB.Net

Hello Everyone and thanks for looking at this. I'm relatively new to vb.net and extremely new to parsing json in vb. I am using JSON.Net and I'm looking to gather data from the following JSON.
http://hastebin.com/bagiyetece.apache
I have classes created for each of the "sections". I am unsure of the correct terminology.
Class One:
Public Class StatsWrapper
Public SummonerID as Long
Public PlayerStatSummaries as playerStatSummaryTypeWrapper
End Class
Class Two:
Public Class playerStatSummaryTypeWrapper
Public playerStatSummaryType As String
Public wins As Long
Public modifyDate As Long
Public aggregatedStats As aggregatedStatsWrapper
End Class
Class Three:
http://hastebin.com/qopanafabe.php
My end goal is to be able to get elements like "totalChampionKills" for the playerStatSummaryType of "Cap5x5" and insert them into a datagridview.
I've been able to correctly parse the following JSON simply by using JObject.Parse.
{"UserName":{"id":84737282,"name":"UserName","profileIconId":660,"summonerLevel":30,"revisionDate":1455686689000}}
To get the id object, I would use:
Dim JSONDerulo = JObject.Parse(JSONResponse)
Dim SummonerID = JSONDerulo(LCase(ToolStripTextBox1.Text))("id")
Where the ToolStripTextBox1.Text is the UserName.
When I try to apply the same logic as above to the larger JSON file in a different sub:
Dim JSONDerulo = JObject.Parse(JSONResponse)
Dim PlayerStatSummaries = JSONDerulo("playerStatSummaries")
Dim Jarray As JArray = PlayerStatSummaries
I can do something like:
For Each obj As JObject In Jarray
TextBox2.Text = TextBox2.Text + Environment.NewLine + obj.ToString + Environment.NewLine
Next
Or call Jarray(1) and parse that again but the list of game types is going to be different for each UserName. I do have a master list for every game type though:
AramUnranked5x5, Ascension, Bilgewater, CAP5x5, CoopVsAI, CoopVsAI3x3, CounterPick, FirstBlood1x1, FirstBlood2x2, Hexakill, KingPoro, NightmareBot, OdinUnranked, OneForAll5x5, RankedPremade3x3, RankedPremade5x5, RankedSolo5x5, RankedTeam3x3, RankedTeam5x5, SummonersRift6x6, Unranked, Unranked3x3, URF, URFBots
If I want to (for example) call AramUnranked5x5.TotalChampionKills or something similar would I have to create a class for each type?
Any suggestions or ideas?
Thanks Again
Note: the json posted is considerably shorter and simpler than the gruesome aggregatedStatsWrapper class linked to depicts! Without data, I cant say whether it is right or not.
Since the aggregatedStats is its own type, nothing very interesting will show for it in a DataGridView, just the type name. There are several ways to handle this. One is to hide the property from the DGV, then when they change selected/current rows, find the new one in the list and set player.aggregatedStats as the selected object in a property grid for a master-detail type view. Playerstatsummary:
Public Class Playerstatsummary
Public Property playerStatSummaryType As String
Public Property wins As Integer
Public Property modifyDate As Long
<Browsable(False)>
Public Property aggregatedStats As Aggregatedstats
Public Property losses As Integer
End Class
<Browsable(False)> will result in the TypeName not being shown in a DGV:
Dim jstr = File.ReadAllText("C:\Temp\myjsonfilename")
Dim jobj = JObject.Parse(jstr)
Dim players = JsonConvert.DeserializeObject(Of List(Of Playerstatsummary))(jobj("playerStatSummaries").ToString)
By Parsing it first, you can skip that outer container. jobj("playerStatSummaries").ToString passes the property data to be deserialized into a List.
You can display what you have very easily without having to loop at all:
dgv1.DataSource = players
It wont yet know about Aggregatedstats unless and until you work out that class exactly. Until then, the type name will display. The post mentions being interested in Cap5x5 only. In that case, a PropertyGrid might be a better UI mechanism (after you find that guy in the list). Result:
(This is from before I added <Browsable(False)> to the class). You could show aggregatedStats as detail like this:
Private Sub DataGridView1_SelectionChanged(...etc
If DataGridView1.SelectedRows.Count = 0 Then Return
Dim thisOne = DataGridView1.SelectedRows(0).Cells(0).Value.ToString
Dim player = players.FirstOrDefault(Function(f) f.playerStatSummaryType = thisOne)
If player IsNot Nothing Then
PropertyGrid1.SelectedObject = player.aggregatedStats
End If
End Sub
In case you are wondering, the date is almost certainly a Unix Epoch date, easily converted to .NET.

Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`

I know there's already a bunch of these questions on SO but none of those answers is working for me. I've been on it all day now and I'm just fried so it's an easy win for the JSON people out there.
The error 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.List`1[FrozenSmoke.WorkflowDescription]' 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<T>) 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 'Workflows', line 1, position 13.
The code is (VB.NET)
Dim z As New List(Of WorkflowDescription)
z = Newtonsoft.Json.JsonConvert.DeserializeObject(Of List(Of WorkflowDescription))(ResponseStatus.Content)
Here is the JSON I'm getting back from the server and is contained in ResponseStatus.Content
{"Workflows":[{"GUID":"594d2946-7bee-49b3-b8bf-e5ee6715a188","Name":"ProcessElectronicContribution"},{"GUID":"fe368a11-2b79-41f9-bee9-edb031612365","Name":"AddActivist"},{"GUID":"4c552492-0014-439d-952b-aeb320e6d218","Name":"AddPartialActivist"}]}
Here is the class
Public Class WorkflowDescription
Public Property Name As String = ""
Public Property GUID As String = ""
End Class
Your json is not simply an array/list but an object container which contains a Workflows property which is a list/array.
{"Workflows":[{"GUID": ....
Workflows is the List/Array but note that it is inside a brace. That is the "outer container".
Public Class WorkFlowContainer
Public Property WorkFlows As List(Of WorkflowItem)
End Class
Public Class WorkflowItem
Public Property Name As String
Public Property GUID As String
End Class
The WorkFlows element in the json will map to the property of the same name. You can get rid of the container after you deserialize:
' ultimate destination
Private myWorkFlows As List(Of WorkflowItem)
...
' elsewhere
Dim jstr = ... ` from whereever
' deserialize to the container
Dim wf = JsonConvert.DeserializeObject(Of WorkFlowContainer)(jstr)
' extract the list
myWorkFlows = wf.WorkFlows
You can ignore the WorkFlowContainer with an extra step in deseriazlizing:
Dim jstr = ... ` from whereever
Dim jopbj - JObject.Parse(jstr)
myWorkFlows = JsonConvert.DeserializeObject(Of List(Of WorkFlows))(jobj("Workflows"))
This way you dont have to define the extra class and dont have to use wf. to get at the data.
You probably know that most arrays can be deserialized as either a List or array. To define Workflows as a property array:
Public Property WorkFlows As WorkflowItem()