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.
Related
I’m on the way to implement an interface to the Ameritrade Rest API in a vb.net application (with httpclient).
Amongst other things, I have to query quotes from a ticker list (e.g. AMD,MSFT,AMZN, ....).
The call of the API works without problems, I get a valid Json back, but the Json is not given back in a way, I would expect.
I now search the best way to handle that problem...
This is not the first interface to a Rest API, I have implemented.
Normally, I implement a corresponding data class in vb.net and then use JsonConvert (from Newtonsoft) to deserialize the Json string into my data class.
Example:
Dim oObject As New DataClass
oObject = JsonConvert.DeserializeObject(Of DataClass)(JsonString)
whereby DataClass is the vb.net class that is defined according to the data in the Json string.
Problem:
The ticker symbol-list to query is dynamic and can change from api call to api call.
If I - e.g. - query AMD and MSFT in a call, I get back (cut to only a few fields) the following 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
}
}
To be able to deserialize the Json, I would have to implement the following DataClass:
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
This would work but is absolutely static and does not make any sense, as I would have to implement a (identical) class for any ticker, I maybe want to query in the feature.
I would expect to get back a dynamic list so that I could implement the class as following:
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
This way, I would be able to deserialize in a List of TickerDetails and the go thru the list (no matter, which symbols I queried).
But, I can’t change, what I get back over the API...
Question:
What is the best way to handle this problem?
You should create a class to represent the a generic stock and then use DeserializeObject to deserialize it into a Dictionary(Of String, [classname]) where the Key represents the stock symbol and the value represents the class.
Take a look at this example:
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)
Example: Live Demo
First thanks for the comments.
I ended up to do it completely different now...
I had further problems with the Ameritrade API:
Some fields are named with leading numbers (52WkHigh and 52WkLow) and
vb.net dev's know, that VB.net don't like properties in classes that
are named with a leading number
So I had to "patch" the received Json data and change the names on the fly to other names ("52WkHigh" to "dble52WkHigh" and "52WkLow" to "dble52WkLow") to be able to deserialize
over the data class, what is not nice
Further, I finally need the data (as fast as possible) in a data table and had "a long way to go":
get data -> deserialize to the data class -> walk thru the data class and overtake the data in the data table.
So.. my new solution (with JObject):
Note: needs:
Imports Newtonsoft.Json.Linq
Code snippets:
Create data table in memory:
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
Parse the Json-String and fill the datatable:
get the data over httpclient (in 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
Additional note: The Ameritrade API gives back the time stamps as long (additional hurdle), but I (and I think also you;-) want it as datetime.
Therefore the Long (I think this data type comes from Java/Unix) has to be "translated" to datetime = vb.net function GetUTCDateFromTimeStamp below:
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
Additional note:
As I want to have the Swiss time, I add one hour to the UTC time.
So.. this a real good solution for me (exactly for the Ameritrade API).
And.. it's blazing fast... (I get 19 tickers with all fields and show the result (data table) in a data grid).
All together took < 1 Second ("felt" about 500 ms)
Hope this helps somebody...
I'm just learning how to work with Json files and my goals are:
Be able to read a Json file
View the info on a TreeView
Be able to Modify, Add, and remove items
Make again the Json File.
For doing this i've learned about Newtonsoft.Json, that helps a lot. I've almost achieved all my goals except being able to add and remove items from my object.
First of all, I load all the Json content to:
Dim ImportedTeams as Teams()
The code for the class objects are the following:
Public Class Teams
Property drivers As Drivers()
Property raceNumber As String
Property CarModel As String
Property ballastKg As String
Property restrictor As String
End Class
Public Class Drivers
Property firstName As String
Property lastName As String
End Class
I have the ImportedTeams with all data filled, from there I get all I need to fill the Treeview, with diferents levels of nodes, etc. Also, I can modify the info stored in the class, and make the Json again. No problems until this point
My problems starts here, when I want to add a new Team. What I tried is the following:
Dim NewTeam As New Teams
Dim NewDriver as New Drivers
With NewDriver
.firstName = TB_Name.text
.lastName = TB_LastName.text
End With
With NewTeam
.drivers = NewDriver()
.raceNumber = NUD_RaceNumbre.Value.ToString
.CarModel = CBB_Car.index
.ballastKg = TB_Ballast.Text
.restrictor = TB_Restrictor.Text
End With
ImportedTeams.append(NewTeam)
This simply wont work. Don't shows up any error, just nothing happens. Also, I don't know how to remove one Team stored in this object.
I also tried to add only a NewTeam, but same problem.
Thanks for your time mates, any help would be appreciated.
As Alex B. said, the solution is easy as follows:
Public Class Teams
Property drivers As **List(of Drivers)**
Property raceNumber As String
Property CarModel As String
Property ballastKg As String
Property restrictor As String
End Class
Public Class Drivers
Property firstName As String
Property lastName As String
End Class
And:
Dim ImportedTeams as **List(of Teams)**
Thanks!
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.
I have a very simple application that I am using to learn move about MVC. In that application I search some data and return a JSON string that I want to use as the model for the view. I just can't seem to figure out how to get the view to consume the JSON as a set of data for it to show on screen.
The code I have so far:
Function Find(term As String) As ActionResult
Dim model As String = SearchData(term)
Return View(model)
End Function
SearchData returns a JSON string that can have one or many objects in it.
How do I now take the JSON returned from SearchData and use it in a view? In fact, when I attempt to add a view it wants to know what model to use. How do i also specific that?
Create a strongly typed object to store you data when parsed
Public Class Data
Public Property ID As Integer
Public Property Term As String
Public Property SomeProperty As String
Public Property SomeOtherProperty As String
End Class
Using a library like JSON.Net, parse the JSON returned from the search.
This assumes a collection of Data is returned from the search.
Imports Newtonsoft.Json;
Function Find(term As String) As ActionResult
Dim json As String = SearchData(term)
Dim model As List(Of Data) = JsonConvert.DeserializeObject(Of List(Of Data))(json)
Return View(model)
End Function
Let the view know to expect the strongly typed model.
#ModelType List(Of Data)
#Code
ViewData("Title") = "Find"
End Code
<h2>MyView</h2>
<!-- rest of view where model can be accessed -->
I am trying to deserialize data from a webserver for a game launcher.
The API docs provide me the data in json format, but I have been struggling to be able to read that data I am given and store it as a variable to use to log in a player. I have also tried a few other things but I am just stuck now. Normally a response from the server would like like this:
{"success":"true","gameserver":"gameserver-alpha.toontownrewritten.com","cookie":"deadbeefdeafbeef0x123"}
The code to deserialize the data:
Dim result() As TTRServerResponse = JsonConvert.DeserializeObject(Of TTRServerResponse())(responseFromServer)
Class with the variables I want to store
Public Class TTRServerResponse
Public Property success As String
Public Property eta As String
Public Property position As String
Public Property queueToken As String
Public Property cookie As String
End Class
Any ideas where I messed up or what I should do? Thanks, Ben.
EDIT: Finally figured it out, I needed to change my result to: Dim result As TTRServerResponse = JsonConvert.DeserializeObject(Of TTRServerResponse) (responseFromServer) I also was returning the data incorrectly to my other sub by returning just result. What I needed to do was return result.success. I now have a better understanding.
You are trying to deserialize the JSON into an array but in your example it is a single object.
So assuming
Dim responseFromServer As String
is equal to
{"success":"true","gameserver":"gameserver-alpha.toontownrewritten.com","cookie":"deadbeefdeafbeef0x123"}
Which, according to the documentation you linked to, is suppose to be a single object,
then you need to update your code to deserialize a single object as appose to an array
Dim result As TTRServerResponse = JsonConvert.DeserializeObject(Of TTRServerResponse)(responseFromServer)