Access Data in Dictionary with deserialized data - json

My program accesses data through a Web API and gets data in JSON format. Response is for example:
{
"response":{
"stationId":"24026900",
"prices":[
{
"name":"Aral Super E10",
"price":"146,90",
"currency":"EUR",
"id":"001131",
"sort":"21"
},
{
"name":"Aral Super 95",
"price":"152,90",
"currency":"EUR",
"id":"001040",
"sort":"22"
},
{
"name":"Aral Ultimate 102",
"price":"172,90",
"currency":"EUR",
"id":"001255",
"sort":"24"
},
{
"name":"Aral Diesel",
"price":"130,90",
"currency":"EUR",
"id":"004002",
"sort":"30"
},
{
"name":"Aral Ultimate Diesel",
"price":"150,90",
"currency":"EUR",
"id":"004267",
"sort":"31"
},
{
"name":"Aral LKW Diesel",
"price":"130,90",
"currency":"EUR",
"id":"004010",
"sort":"32"
}
],
"lastUpdate":"202104122030",
"disabled":"false",
"openNow":"Wir haben f\u00fcr Sie ge\u00f6ffnet."
}
}
How can I e.g. access deeply nested data like "price":"172,90".
My structure is like:
Dim sJSON As String
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim PriceLastValue As String = funcGetPriceInfo("response") 'How to get access to deeper nested data here?
'
'Every key except "response" throws an exception
'
MsgBox(PriceLastValue.ToString)
End Sub
Private Function funcGetPriceInfo(ByVal sVal As String) As String
Dim JSONSerializer As New System.Web.Script.Serialization.JavaScriptSerializer
sJSON = ReadStreamFromWeb.ReadFileFromWeb_WebRequest("http://ap.aral.de/api/v2/getStationPricesById.php?stationId=24026900")
Dim dictJSON As Dictionary(Of String, Object) = JSONSerializer.Deserialize(Of Dictionary(Of String, Object))(sJSON)
Return dictJSON(sVal).ToString
End Function

thank you, really appreciate your help! Now added reference to Newtonsoft and the classes:
Public Class Rootobject
Public Property response As Response
End Class
Public Class Response
Public Property stationId As String
Public Property prices() As Price
Public Property lastUpdate As String
Public Property disabled As String
Public Property openNow As String
End Class
Public Class Price
Public Property name As String
Public Property price As String
Public Property currency As String
Public Property id As String
Public Property sort As String
End Class
And trying to get the object:
sJSON = ReadStreamFromWeb.ReadFileFromWeb_WebRequest("http://ap.aral.de/api/v2/getStationPricesById.php?stationId=24026900")
Dim obj As Rootobject = JsonConvert.DeserializeObject(Of Rootobject)(sJSON)
But this throws..
Newtonsoft.Json.JsonSerializationException: "Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'myprog.Form1+Price' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.

Related

Extract data from a JSON received from an HTTP response

So I have an HTTP response that gives me this data:
{
"result":"success",
"records":{
"509442013":{
"nif":509442013,
"seo_url":"nexperience-lda",
"title":"Nexperience Lda",
"address":"Rua da Lionesa Nº 446, Edifício G20",
"pc4":"4465",
"pc3":"671",
"city":"Leça do Balio",
"activity":"Desenvolvimento de software. Consultoria em informática. Comércio de equipamentos e sistemas informáticos. Exploração de portais web.",
"status":"active",
"cae":"62010",
"contacts":{
"email":"info#nex.pt",
"phone":"220198228",
"website":"www.nex.pt",
"fax":"224 905 459"
},
"structure":{
"nature":"LDA",
"capital":"5000.00",
"capital_currency":"EUR"
},
"geo":{
"region":"Porto",
"county":"Matosinhos",
"parish":"Leça do Balio"
},
"place":{
"address":"Rua da Lionesa Nº 446, Edifício G20",
"pc4":"4465",
"pc3":"671",
"city":"Leça do Balio"
},
"racius":"http://www.racius.com/nexperience-lda/",
"alias":"Nex - Nexperience, Lda",
"portugalio":"http://www.portugalio.com/nex/"
}
},
"nif_validation":true,
"is_nif":true,
"credits":{
"used":"free",
"left":[
]
}
}
And I need to extract some data from it, like the fields:
NIF
title
and the email and phone that are inside the contacts array.
I need the data to populate some TextBoxes in my Form.
To get the http response I have this button but I don't know how to extract the data I need.
Can someone help me?
My code:
Private Sub Btn_NIFImport_Click(sender As Object, e As EventArgs) Handles Btn_NIFImport.Click
Dim key As String = "xxxxxxxxxxxxxxxxxxxxxxxxxx"
Try
'Create the request
Dim request As HttpWebRequest = HttpWebRequest.Create("http://www.nif.pt/?json=1&q=" & Txt_NIFImport.Text & "&key=" & key)
request.Proxy = Nothing
request.UserAgent = "Test"
'Create the response reader
Dim response As HttpWebResponse = request.GetResponse
Dim responseStream As System.IO.Stream = response.GetResponseStream
'Create a new stream reader
Dim streamReader As New System.IO.StreamReader(responseStream)
Dim data As String = streamReader.ReadToEnd
streamReader.Close()
'Display the data on the screen
Txt_Teste.Text = data
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Thanks in advance.
after you get the response from the http request you need to deserialize the json to an object in vb.net
To Classes to create the object by your json:
Public Class [Structure]
Public Property nature As String
Public Property capital As String
Public Property capital_currency As String
End Class
Public Class Geo
Public Property region As String
Public Property county As String
Public Property parish As String
End Class
Public Class Place
Public Property address As String
Public Property pc4 As String
Public Property pc3 As String
Public Property city As String
End Class
Public Class Record
Public Property nif As Integer
Public Property seo_url As String
Public Property title As String
Public Property address As String
Public Property pc4 As String
Public Property pc3 As String
Public Property city As String
Public Property activity As String
Public Property status As String
Public Property cae As String
Public Property contacts As Contacts
Public Property [structure] As [Structure]
Public Property geo As Geo
Public Property place As Place
Public Property racius As String
Public Property [alias] As String
Public Property portugalio As String
End Class
Public Class Credits
Public Property used As String
Public Property left As List(Of Object)
End Class
Public Class Root
Public Property result As String
Public Property records As Dictionary(Of String, Record)
Public Property nif_validation As Boolean
Public Property is_nif As Boolean
Public Property credits As Credits
End Class
and to deserialize added after you get the response the following line:
Root l = JsonConvert.DeserializeObject<Root>(response);
EDIT:
I made some changes in the code so now you use with Dictionary that has KEY in your json '509442013' and value As Record (Notice that I change the class name as was before '_509442013')
And in the root changes
Public Property records As Dictionary(Of String, Record)
now this will work in each time even if you will get in each http request ID as class that not the same.
notice that the only way you can get the value is by the KEY you already pass in the http request.
Added GIF:
(In my case I change the ID and city, in the result show the city from the json)
Convert Button:
Dim jsonString As String = tbInput.Text
Dim l As Root = JsonConvert.DeserializeObject(Of Root)(jsonString)
tbResult.Text = l.records(tbKEY.Text.ToString).city.ToString()
tbKEY get the value from the screen like in my gif example.

Convert JSON object and array to same class in VB.net

I am trying to convert a JSON returned from a third party API, into VB.NET class object. The problem is that the JSON sometimes returns a node as an Array of objects and sometimes the same node as an single Object. So, while trying to convert when it receives Array of objects, the code throws exception.
{
"correlation_id": "228.9219622269229",
"Error": {
"messages": [
{
"code": "401",
"description": "Unauthorized"
}
]
},
"transaction_status": "Not Processed"
}
As you can see, there is an array of Error messages under Error->messages node. But sometimes, the JSON returned is simpy and object of Error messages something like
{
"correlation_id": "228.9219622269229",
"Error": {
"messages": {
"code": "401",
"description": "Unauthorized"
}
},
"transaction_status": "Not Processed"
}
I try to deserialize this JSON to the following class
Public Class PayeezyRefundResponse
Public correlation_id As String
Public transaction_status As String
Public validation_status As String
Public transaction_type As String
Public transaction_id As String
Public transaction_tag As String
Public bank_resp_code As String
Public bank_message As String
Public [Error] As PayeezyError
End Class
Public Class PayeezyError
Public messages As PayeezyErrorMessages()
End Class
Public Class PayeezyErrorMessages
Public code As String
Public description As String
End Class
But when the JSON returns Error message as single object, the code throws exception on PayeezyError class. How can I convert the JSON to this class so that it works in both the cases (i.e. with Array of objects and with single Object) ?
You can build a custom converter that can handle both cases as a List(Of PayeezyErrorMessage).
This converter always returns a List(Of PayeezyErrorMessage), even when the JSON contains a single object.
Note: in code, PayeezyErrorMessages, plural, has been renamed to PayeezyErrorMessage, single, since this class generates a single object.
The custom converter is added to the property as an attribute:
<JsonConverter(GetType(PayeezyErrorsConverter(Of PayeezyErrorMessage)))>
Public Messages As List(Of PayeezyErrorMessage)
Refactored code:
Public Class PayeezyRefundResponse
' [...]
<JsonProperty("Error")>
Public Errors As PayeezyErrors
End Class
Public Class PayeezyErrors
<JsonProperty("messages")>
<JsonConverter(GetType(PayeezyErrorsConverter(Of PayeezyErrorMessage)))>
Public Messages As List(Of PayeezyErrorMessage)
End Class
Public Class PayeezyErrorMessage
Public code As String
Public description As String
End Class
Custom converter:
► The writer part is not implemented, since you probably won't need to send back this JSON
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
Public Class PayeezyErrorsConverter(Of T)
Inherits JsonConverter
Public Overrides Function CanConvert(objectType As Type) As Boolean
Return (objectType = GetType(List(Of T)))
End Function
Public Overrides Function ReadJson(reader As JsonReader, objectType As Type, existingValue As Object, serializer As JsonSerializer) As Object
Dim token As JToken = JToken.Load(reader)
If token.Type = JTokenType.Array Then
Return token.ToObject(Of List(Of T))()
End If
Return New List(Of T)() From {
token.ToObject(Of T)()
}
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

Deserialize this JSON string

I always get the error:
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[Test.Form15+results[]]' 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.
My code is as follows and i'm not sure if it's the double-quotes causing the issues, or the bracket at the start of the json string. Any tips would be appreciated.
Public Class Form15
Public Class UTicketContact
<JsonProperty("display_value")>
Public Property DisplayValue As String
<JsonProperty("link")>
Public Property Link As String
End Class
Public Class URequestedFor
<JsonProperty("display_value")>
Public Property DisplayValue As String
<JsonProperty("link")>
Public Property Link As String
End Class
Public Class AssignedTo
<JsonProperty("display_value")>
Public Property DisplayValue As String
<JsonProperty("link")>
Public Property Link As String
End Class
Public Class OpenedBy
<JsonProperty("display_value")>
Public Property DisplayValue As String
<JsonProperty("link")>
Public Property Link As String
End Class
Public Class AssignmentGroup
<JsonProperty("display_value")>
Public Property DisplayValue As String
<JsonProperty("link")>
Public Property Link As String
End Class
Public Class Result
<JsonProperty("u_ticket_contact")>
Public Property UTicketContact As UTicketContact
<JsonProperty("u_requested_for")>
Public Property URequestedFor As URequestedFor
<JsonProperty("assigned_to")>
Public Property AssignedTo As AssignedTo
<JsonProperty("opened_by")>
Public Property OpenedBy As OpenedBy
<JsonProperty("assignment_group")>
Public Property AssignmentGroup As AssignmentGroup
End Class
Public Class results
<JsonProperty("result")>
Public Property Result As Result()
End Class
Function FindRequestedFor(ByVal instancename As String,
ByVal rtask As String) As String
Dim requestedfor As String = ""
'Dim byteArray As Byte() = Encoding.UTF8.GetBytes(postData)
Dim accessToken As String = GenerateToken("instancenameredacted",
"clientIdredacted",
"clientSecretredacted",
"accountredacted",
"accountpasswordredacted")
Dim url As String = "https://" & instancename & ".service-now.com/api/ubis2/request/rtask?query=number%3D" & rtask
Dim request As WebRequest = WebRequest.Create(url)
Dim dataStream As Stream
request.ContentType = "application/json; charset=utf-8"
request.Method = "GET"
request.Headers.Add("Authorization", "Bearer " & accessToken)
dataStream = request.GetResponse.GetResponseStream
Dim reader As New StreamReader(dataStream)
Dim responseFromServer As String = reader.ReadToEnd
'Format of the JSON string is: ""{
""result"": [
{
""u_ticket_contact"": {
""display_value"": ""Name1"",
""link"": ""https://instance.service-now.com/api/now/table/sys_user/470104cf600ad400808370bee6ad2596""
},
""u_requested_for"": {
""display_value"": ""Name2"",
""link"": ""https://instance.service-now.com/api/now/table/sys_user/470104cf600ad400808370bee6ad2596""
},
""assigned_to"": {
""display_value"": ""Name3"",
""link"": ""https://instance.service-now.com/api/now/table/sys_user/98c7a3e5ac723040773cf2044a10de0c""
},
""opened_by"": {
""display_value"": ""Name4"",
""link"": ""https://instance.service-now.com/api/now/table/sys_user/470104cf600ad400808370bee6ad2596""
},
""assignment_group"": {
""display_value"": ""Group Name1"",
""link"": ""https://instance.service-now.com/api/now/table/sys_user_group/bad979fa19c44a40b5a0d99e2b982e75""
}
}
]
}""
Console.WriteLine(responseFromServer)
reader.Close()
dataStream.Close()
Dim test = JsonConvert.DeserializeObject(Of List(Of results()))(responseFromServer)
End Function
end class
I would use List(Of Result) type with initialization as below:
Public Class results
<JsonProperty("result")>
Public Property Result As New List(Of Result)
End Class

Deserialize this json in VB.NET

I have this json response:
{
"tracked_until": "1483704963",
"solo_competitive_rank": "4066",
"competitive_rank": "3821",
"mmr_estimate": {
"estimate": 3971,
"stdDev": 215.26495302301302,
"n": 20
},
"profile": {
"account_id": 131505839,
"personaname": "LeG",
"name": null,
"cheese": 1,
"steamid": "76561198091771567",
"avatar": "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/c0/c09ca9b316ff7bf7dccba6f5a32aba97b8dba05c.jpg",
"avatarmedium": "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/c0/c09ca9b316ff7bf7dccba6f5a32aba97b8dba05c_medium.jpg",
"avatarfull": "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/c0/c09ca9b316ff7bf7dccba6f5a32aba97b8dba05c_full.jpg",
"profileurl": "http://steamcommunity.com/id/LegLabs/",
"last_login": "2016-11-11T13:13:18.651Z",
"loccountrycode": "AL"
}
}
Using an Online Tool, I created these classes:
<Serializable>
Public Class mmr_estimate
Public Property estimate As String
Public Property stdDev As String
Public Property n As String
End Class
<Serializable>
Public Class profile
Public Property account_id As String
Public Property personaname As String
Public Property name As String
Public Property cheese As String
Public Property steamid As String
Public Property avatar As String
Public Property avatarmedium As String
Public Property avatarfull As String
Public Property profileurl As String
Public Property last_login As String
Public Property loccountrycode As String
End Class
<Serializable>
Public Class RootObject
Public Property tracked_until As String
Public Property solo_competitive_rank As String
Public Property competitive_rank As String
Public Property mmr_estimate As mmr_estimate
Public Property profile As profile
End Class
Then I use this code to deserialize it:
Dim steamData As String = ' the json contents above
Dim myjss As New JavaScriptSerializer()
Dim playerDictionary = myjss.Deserialize(Of List(Of RootObject))(steamData)
But the result I get is nothing, playerDictionary has 0 items, when it should have 1 item with the contents of the json parsed into KeyValuePairs.
If I use this piece of code
Dim data = myjss.DeserializeObject(steamData)
and then run a for each loop on the data elements, I can see the contents of data when debugging, but I don't know how to work with them like that, since they are just objects which I'm having trouble converting into KeyValuePairs, who in themselves may contain arrays of KeyValuePairs.
What I'm trying to get is the values of solo_competitive_rank, competitive_rank and steamid, but if I can't get the whole contents deserialized, I can't do that.
Are the declared classes wrong?
but with this solution you use not the class RootObject.
With first method, your JSON want in the list with key and value.
This is only for JSON Array. :(
rg

Deserializing multiple objects in json string

I am consuming a web service that is sending multiple objects in a json string.
{ "id": null, "method": "ready", "params": [ { "accept": 1, "serial": "001d50101979" },
{
"result": {
"serial": "001d50101979",
"name": "001d50101979",
"model": "HMP200",
"mode": "normal",
"firmware": {
"version": "3.2.2-1.0.28801",
"status": "normal"
},
"uptime": "233.50",
"bootid": "e62f7839-95b1-4775-8476-c0b1b5b4857f"
},
"error": null,
"id": 1231
} ] }
I am using the following classes
Public Class Firmware
Public Property version As String
Public Property status As String
End Class
Public Class Result
Public Property serial As String
Public Property name As String
Public Property model As String
Public Property mode As String
Public Property firmware As Firmware
Public Property uptime As String
Public Property bootid As String
End Class
Public Class Param
Public Property accept As Integer
Public Property serial As String
End Class
Public Class Player
Public Property id As Object
Public Property method As String
Public Property params As Param()
End Class
I have no issue deserializing the root class Player but I am not sure how to deserialize the class Result.
Dim Player As New Player
Player = Newtonsoft.Json.JsonConvert.DeserializeObject(Of Player)(JsonString)
Dim FirmwareVersion As String = Player.id
Dim bootid As String = Player.method
Dim Model As String = Player.params(0).accept
Dim Serial As String = Player.params.ElementAt(0).serial
Change your class Param to
Public Class Param
Public Property accept As Integer
Public Property serial As String
Public Property result As Result
End Class
then you can access your result like so
Dim Player As New Player
Player = Newtonsoft.Json.JsonConvert.DeserializeObject(Of Player)(JsonString)
Dim FirmwareVersion As String = Player.id
Dim bootid As String = Player.method
Dim Model As String = Player.params(0).accept
Dim Serial As String = Player.params.ElementAt(0).serial
For Each p In Player.params
If p.result IsNot Nothing Then
Console.WriteLine(p.result.model)
End If
Next