Add and remove data from object class - json

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!

Related

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

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...

JSON - Conversion to VB.NET Object

I am new to JSON strings so I am having a hard time with it.
I am used to SOAP Web Services where in Visual Studio automatically creates the strongly typed Classes for me in the background.
JSON - REST Web Services are for me is much tedious as I have to create manually the equivalent Strongly Typed Classes. (Or I maybe wrong).
I have this JSON String being returned to me by a REST Web Service:
{"Message":"The request is invalid.","ModelState":{"command":["Required property 'Vendor' not found in JSON. Path '', line 1, position 310."],"command.Terms":["The Terms field is required."]}}
Could you guide me on the equivalent Class?
Appreciate your help!
Regards,
Jake
assuming you are using JSON.NET...
Public Class Response
Public Property Message As String
Public Property ModelState As ModelState
End Class
Public Class ModelState
<JsonProperty("command")>
Public Property Command As List(Of String) = New List(Of String)
<JsonProperty("command.Terms")>
Public Property Terms As List(Of String) = New List(Of String)
End Class
Usage:
Dim response As Response = JsonConvert.DeserializeObject(jsonString)

Deserializing Json VB.NET

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)

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.

Does the business logic for deserializing a JsonPayload have to match?

I am currently attempting to deserialize a Json Payload that has been fired from a webhook URL on an MVC application, but I do not know if the business logic provided has to match exactly to prevent any null values.
Basically the Json Payload contains way to much useless information that I do not what to display. This is a brief preview of what the Payload looks like:
"webhookEvent":"jira:issue_updated",
"user":{
"self":"http://gtlserver1:8080/rest/api/2/user?username=codonoghue",
"name":"codonoghue",
"issue":{
"id":"41948",
"self":"http://gtlserver1:8080/rest/api/2/issue/41948",
"key":"OP-155",
"fields":{
"summary":"Test cc recipient",
"progress":{
"progress":0,
"total":0}, ....
I only want to display information about the issue and the other information is just white noise to me and don't want to use it. Now do I have to create classes only for the issue details etc like this:
Public Class jiraIssue
Public Property id As String
Public Property key As String
Public Property fields As jiraFields
End Class
Or do I have to make sure to provide sufficient business logic about the User class just to make sure that it will be received correctly? I also know that using Json2csharp.com the classes that can be made are user, issue, fields, progress as well as the overall RootObject, so I also want to know is do these classes need to contain the exact same matching variables as the JsonPayload, e.g. I don't want progress to have the variable total.
When using Json2csharp that in every class they contain an ID variable with the property as string and I would like to know if this is needed in the classes to be able to display the information or can I not use it as it is also irrelevant.
The main thing that I want to deserialize is the RootObject, which contains a webhookEvent (string) an issue (which links to issue class, which links to fields class which links to all relevant information), comment which links to a comment class. I want to deserialize this so would this be correct?
Public Class Rootobject
Public Property webhookEvent As String
Public Property issue As Issue
Public Property comment As Comment2
Public Property timestamp As Long
End Class
Public Class Issue
Public Property key As String
Public Property fields As Fields
End Class
Public Class Fields
Public Property issueType as IssueType
Public Property summary As String
Public Property summary As String
End Class
Dim Issue As RootObject = New System.Web.Script.Serialization.JavaScriptSerializer().Deserialize(Of RootObject)(json)
For Each item As var In Issue.issue
Console.WriteLine("WebhookEvent: {0}, issue: {1}", item.WebhookEvent, item.issue)
Next
Update
It seems that the problems that I was having was due to the JsonPayload itself, the business logic did not affect. There were issues with the incompatible characters, some fields were null and could not be and a few others as well.
I have correctly got my Json payload correctly read in and the Json Payload information does not have to correctly match up with the classes that you create. You only have to create classes and variables for the information that you need from the Json Payload. For example if you did not want the information on comments do not create a comment class.
Public Class Rootobject
Public Property webhookEvent As String
Public Property issue As Issue
' Public Property comment As Comment2
' comment out the comment class because it is not needed
Public Property timestamp As Long
End Class