Simple JSON deserialisation for dummies - vb.net

Trying to deserialise the following json returned from a web source:
{
"cards": [
{
"high": "8.27",
"volume": 5,
"percent_change": "0.00",
"name": "Wurmcoil engine",
"url": "http://blacklotusproject.com/cards/Scars+of+Mirrodin/Wurmcoil+Engine/",
"price": "6.81",
"set_code": "SOM",
"average": "5.67",
"change": "0.00",
"low": "1.12"}],
"currency": "USD"
}
I am using json.net with visual basic, new to both of them, especially the object oriented portions of vb. I would just like to extract the 'price' variable.
I have set up a class as such:
Public Class Card
Public high As String
Public volume As String
Public percent_change As String
Public name As String
Public url As String
Public price As String
Public set_code As String
Public average As String
Public change As String
Public low As String
End Class
The code I am currently using is:
Public Sub parse_json(url As String)
Dim blp_json As String = ""
Dim wClient As New WebClient
wClient.Proxy = System.Net.HttpWebRequest.DefaultWebProxy
blp_json = wClient.DownloadString(url)
MessageBox.Show(blp_json)
Dim card_1 = Newtonsoft.Json.JsonConvert.DeserializeObject(Of Card)(blp_json)
PriceTextBox.Text = card_1.price
TextBox1.AppendText(card_1.ToString)
TextBox1.AppendText(blp_json)
End Sub
Just trying many different things to get a hang of it, not really sure what I am doing. I presume my Card class is incorrect as 'price' appears to be nested in cards:[{...}]
I don't really know about deserialising json at all, and much less about how to do it /properly/ in vb.

I use the System.Web.Script.Serialization.JavaScriptSerializer for JSON deserialization. Your example is slightly complicated by the fact that cards contains an array of JSON objects. This is indicated by the "[" and "]". This example code will show you how to process it regardless of whether cards is an array or not. You may wish to ignore the Else if you are sure that there will always be an array in cards
Make sure that you have included a reference to System.Web.Extensions in your project and...
Imports System.Web.Script.Serialization
and then...
Dim MySerializer As JavaScriptSerializer = New JavaScriptSerializer()
Dim dictResult As Dictionary(Of String, Object) = MySerializer.Deserialize(Of Dictionary(Of String, Object))(blp_json)
Dim dictCard As Dictionary(Of String, Object)
If dictResult.ContainsKey("cards") Then
If TypeOf dictResult("cards") Is ArrayList Then
Dim arrResult As ArrayList = DirectCast(dictResult("cards"), ArrayList)
For Each arrCardRecord In arrResult
dictCard = DirectCast(arrCardRecord, Dictionary(Of String, Object))
If dictCard.ContainsKey("price") Then Console.WriteLine(dictCard("price"))
Next
Else
dictCard = DirectCast(dictResult("cards"), Dictionary(Of String, Object))
If dictCard.ContainsKey("price") Then Console.WriteLine(dictCard("price"))
End If
End If

Related

VB.NET Json request

Having some trouble trying to convert my json data to something usable
my json data
{
"4": {
"name": "Warehouse",
"tenantcode": "242",
"package_id": 1,
"package": "package10",
"ext_length": 4,
"country_id": 91,
"country_code": 61
},
"5": {
"name": "Partners",
"tenantcode": "240",
"package_id": 1,
"package": "package10",
"ext_length": 4,
"country_id": 91,
"country_code": 61
},
"8": {
"name": "Systems",
"tenantcode": "241",
"package_id": 20,
"package": "Systems",
"ext_length": 4,
"country_id": 91,
"country_code": 61
},
VB code
Imports System.Net
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim json2 As String = (New WebClient).DownloadString("https://myapi")
Dim json As String = json2
Dim ser As JObject = JObject.Parse(json)
Dim data As List(Of JToken) = ser.Children().ToList
For Each item As JProperty In data
item.CreateReader()
Select Case item.Name
Case "Name"
this is a far as i got.
i need to know whats the best was to try and use my json data.
build a new class?
Yes, you should build a new class. The data you provided can be deserialized as a Dictionary, so you'd just have to make a class for the details.
Public Class Details
Public Property Name As String
Public Property Tenantcode As String
Public Property Package_id As Integer
Public Property Package As String
Public Property Ext_length As Integer
Public Property Country_id As Integer
Public Property Country_code As Integer
End Class
Then simply deserialize your data into a Dictionary(String, Details)
Dim data = JsonConvert.DeserializeObject(Of Dictionary(Of String, Details))
Visual Studio has a cool feature called Paste JSON as Classes that can be found under Edit > Paste Special > Paste JSON as Classes. If you were to do this, then you would get something that looks like the following:
Public Class Rootobject
Public Property _4 As _4
Public Property _5 As _5
End Class
Public Class _4
Public Property name As String
Public Property tenantcode As String
Public Property package_id As Integer
Public Property package As String
Public Property ext_length As Integer
Public Property country_id As Integer
Public Property country_code As Integer
End Class
Public Class _5
Public Property name As String
Public Property tenantcode As String
Public Property package_id As Integer
Public Property package As String
Public Property ext_length As Integer
Public Property country_id As Integer
Public Property country_code As Integer
End Class
Since the Rootobject is basically acting like an associative array (in PHP) or dictionary (in .NET), then what I would do is get rid of Rootobject and _4, and rename _5 to be something a little more generic. Also, you can use decorators to make the property names conform to a more .NET style if you wanted:
Public Class Record
<JsonProperty("name")>
Public Property Name As String
<JsonProperty("tenantcode")>
Public Property TenantCode As String
<JsonProperty("package_id")>
Public Property PackageId As Integer
<JsonProperty("package")>
Public Property Package As String
<JsonProperty("ext_length")>
Public Property ExtLength As Integer
<JsonProperty("country_id")>
Public Property CountryId As Integer
<JsonProperty("country_code")>
Public Property CountryCode As Integer
End Class
Now what you'd do is create your webclient, download the string, and use DeserializeObject to convert the associative array to a dictionary:
Dim records As Dictionary(Of Integer, Record)
Using client As New WebClient()
Dim payload As String = client.DownloadString("https://myapi")
records = JsonConvert.DeserializeObject(Of Dictionary(Of Integer, Record))(payload)
End Using
Now you can get the object by it's key and access it's properties. E.g.:
If (records.ContainsKey(4)) Then
Console.WriteLine(records(4).Name)
End If

Using classes for JSON serialization

All,
I need some help with understanding how classes can work with vb.NET and JSON.NET. I'm completely new to this. I've tried searching for answers, but I'm probably not asking the right questions. Here's my dilemma:
I have a JSON that I need to send to a REST API.
{
"paInfo":[
{
"providerAccountName":"someClient",
"providerAccountDescription":"A fine client.",
"providerName":"provider",
"externalProviderIdentifier":"BU4377890111"
},
{
"providerAccountName":"someClient1",
"providerAccountDescription":"A fine client.",
"providerName":"provider",
"externalProviderIdentifier":"BU4377890111"
}
],
"hubAccountName":"test"
}
I ran this through https://jsonutils.com/ to build my class as:
Public Class PaInfo
Public Property providerAccountName As String
Public Property providerAccountDescription As String
Public Property providerName As String
Public Property externalProviderIdentifier As String
End Class
Public Class addHubAcct
Public Property paInfo As PaInfo()
Public Property hubAccountName As String
End Class
From there, I'm trying to assign values to the class properties, but I don't quite understand how to pass the values for PaInfo to the property. Below is a snippet of code I'm using to assign values. If I try to assign a.paInfo = p, it errors:
error BC30311: Value of type 'PaInfo' cannot be converted to
'PaInfo()'
If I don't pass anything through to a.paInfo, I get a zero-length string in the JSON serialization.
Private Sub serializeAcct()
Dim p As New PaInfo
Dim a As New addHubAcct
p.providerAccountName = "Test\name'This ""that and the other'"
p.providerAccountDescription = "acct desc"
p.providerName = "tester"
p.externalProviderIdentifier = "123456"
a.hubAccountName = "Tester"
a.paInfo = p 'Here's my hangup
Dim o As String = JsonConvert.SerializeObject(a)
Dim deserializedProduct As addHubAcct = JsonConvert.DeserializeObject(Of addHubAcct)(o)
Stop
End Sub
?o.tostring,nq
{"paInfo":null,"hubAccountName":"Tester"}
Change the addHubAcct class like this:
Public Class addHubAcct
Public Property paInfo As New List(Of PaInfo)()
Public Property hubAccountName As String
End Class
And then change the bad line in serializeAcct() like this:
a.paInfo.Add(p)
You likely have other problems as well, but that should get you past the current obstacle.
Using List and .ToArray is what I was missing with my original code.
Private Sub serializeAcct()
Dim p1 As New PaInfo
Dim ps As New List(Of PaInfo)
Dim a As New addHubAcct
p1.providerAccountName = "Test\name'This ""that and the other'"
p1.providerAccountDescription = "acct desc"
p1.providerName = "tester"
p1.externalProviderIdentifier = "123456"
ps.Add(p1)
a.hubAccountName = "Tester"
a.paInfo = ps.ToArray
Dim o As String = JsonConvert.SerializeObject(a)
End Sub

Access deserialize JSON and avoid var declaration

I'm completely new to vb (started about 2 hours ago) and I'm trying to convert a php application to vb to circumnavigate some unavoidable problems.
However I'm trying to get a response from a server that returns a JSON string as page source(everythng is fine untill here), my problem is that I don't understand exactly how to access the deserialized object.
This is the response:
{
"response":{
"a":"boolean",
"b":"string",
"c":"string",
"d":"string",
"e":"string",
"f":"string",
"profile":{
"h":"decimal",
"i":"string",
"l":"string",
"m":"string",
"n":"string",
"o":"string",
"p":"string",
"q":"string"
}
}
}
Current vb code:
Public Class Form1
...
Dim jsonResponse As String = New System.Net.WebClient().DownloadString(url)
Dim r As LoginReturn = JsonConvert.DeserializeObject(Of LoginReturn)(jsonResponse)
...
End Sub
Public Class LoginItem
Public a As Boolean
Public apikey As String
Public c As String
Public d As String
Public e As String
Public f As String
Public Property profile As List(Of LoginProfile)
End Class
Public Class LoginProfile
Public h As Decimal
Public i As String
Public l As String
Public m As String
Public n As String
Public o As String
Public p As String
Public q As String
End Class
Public Class LoginResponse
Public Property response As List(Of LoginItem)
End Class
Public Class LoginReturn
Public Property value As List(Of LoginResponse)
End Class
From all those infomation I only need apikey so I tried to access it with these
r.value.response.apikey
r.value(0).response.apikey
Both returns this error:
'apikey' is not a memeber of 'System.Collections.Generic.List(Of WindowsApplication1.LoginItem)'.
Previously with php I used this:
$r = json_decode(file_get_contents($url));
$_SESSION['a']=$r->response->apikey
So my questions are:
How do I access that information?
Do I need to declare all those variables even if I don't need them?
EDIT SOLUTION
'Get Json
Dim jsonResponse As String = New System.Net.WebClient().DownloadString(url)
'Parse Json
Dim r As JObject = JObject.Parse(jsonResponse)
'Access Json
GlobalVar.api = r("response")("apikey")
This will show you how to parse the raw JSON so you can pluck out the part you are interested in. Since you only want one thing, you can use JObject.Parse and forego the classes to get what you want.
' you would get it from the webclient
Dim jstr As String = File.ReadAllText("C:\Temp\logresp.json")
Dim api = obj("response")("b")
To read something else, just change the key to whatever item you want. For instance, to read "q":
Dim QItem = obj("response")("profile")("q")
Since q is a property of profile, which itself is a child of response you have to dig deeper.
If you do end up needing many things, your classes are not quite right for parsing into a class (DeserializeObject). Look at the JSON and you'll see there is no property named "APIKey". Going by position, it is called "b". This might be an artifact of changing things around for posting here, but I can only go by what is posted.

Download Files From Web Server

I have the following response from a URL. How do I code to download the two files to my hard drive with the name = id.
HTTP/1.1 200 OK
Content-Type: application/json
{
"files": [
{
"format": "fillz-order-tab",
"checksum": "6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b",
"acknowledged": false,
"uri": "https://file-api.fillz.com/v1/orders/created/20140611T003336Z-8b975127",
"date_created": "20140611T003336Z",
"id": "20140611T003336Z-8b975127"
},
{
"format": "fillz-order-tab",
"checksum": "d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35",
"acknowledged": false,
"uri": "https://file-api.fillz.com/v1/orders/created/20140611T013545Z-3e2f2083",
"date_created": "20140611T013545Z",
"id": "20140611T013545Z-3e2f2083"
}
]
}
My code that calls the URL is the following:
Using response As HttpWebResponse = TryCast(request.GetResponse(), HttpWebResponse)
Dim reader As New StreamReader(response.GetResponseStream())
result = reader.ReadToEnd()
I am using json.net with visual basic 2008.
These are my classes
Public Class file
Public format As String
Public checksum As String
Public acknowledged As String
Public uri As String
Public date_created As String
Public id As String
End Class
Public Class RootObject
Public Property files() As List(Of file)
Get
End Get
Set(ByVal value As List(Of file))
End Set
End Property
End Class
This is my code to deserializare json results
Dim res As RootObject = JsonConvert.DeserializeObject(Of FillzAPI.FileAPI.RootObject)(result)
I want to read each id from the url response
For Each Data As FileAPI.RootObject In res
Next
I have the next error:
Expression is of type 'FillzAPI.FileAPI.RootObject', which is not a collection type.
How do I fix this error?
A few points which will give you working code:
There is an easier way to download the JSON data.
You've accidentally
declared RootObject.files as an array of lists, and its Get and
Set methods are empty.
File is an unfortunate name for a class as
it conflicts with System.IO.File.
It would be better to have the
things in (what I named) FileData as properties. You can take
advantage of auto-declared properties and not have to type the
Get/Set methods.
Putting all those together, I arrived at
Option Infer On
Imports System.IO
Imports System.Net
Imports Newtonsoft.Json
Module Module1
Public Class FileData
Public Property format As String
Public Property checksum As String
Public Property acknowledged As String
Public Property uri As String
Public Property date_created As String
Public Property id As String
End Class
Public Class RootObject
Public Property Files As List(Of FileData)
End Class
Sub Main()
' I set this up on a local web server. Adjust as required.
Dim src = "http://127.0.0.1/JsonSample.txt"
' An easy way to get a string from a web server...
Dim wc As New WebClient
'TODO: Try..Catch any error that wc.DownloadString throws.
Dim jsonData = wc.DownloadString(src)
'TODO: Try..Catch any error that JsonConvert.DeserializeObject throws.
Dim y = JsonConvert.DeserializeObject(Of RootObject)(jsonData)
' Somewhere to save the downloaded files...
Dim dest = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "My JSON test")
If Not Directory.Exists(dest) Then
Directory.CreateDirectory(dest)
End If
For Each x In y.Files
Console.WriteLine(x.uri)
'TODO: Try..Catch any error that wc.DownloadFile throws. Also perhaps use async methods.
wc.DownloadFile(x.uri, Path.Combine(dest, x.id))
Next
Console.ReadLine()
End Sub
End Module
Which outputs
https://file-api.fillz.com/v1/orders/created/20140611T003336Z-8b975127
https://file-api.fillz.com/v1/orders/created/20140611T013545Z-3e2f2083
and saves the files.

What type to use for an array of JSON objects?

I have a WCF service that receives a JSON payload.
For instance, a payload like this:
{ "a":"123", "b":"xyz" }
Works well with the following service method signature:
<OperationContract()>
Public Sub SomeMethod(ByVal a As Integer, ByVal b As String)
a and b are automatically casted to an Integer and a String respectively.
However, now I need to send a slightly more complex argument to the service method, one that isn't an Integer or a String:
{ "a":"123", "b":"xyz", "c":"[ { "key":"1", "val":"2" }, { "key":"2", "val":"3" } ]" }
Basically, c is an array of objects containing key-value pairs (i.e. JSON objects). So, what type do I declare c as in the service method signature? I'm not really familiar with VB, so I don't know what types are available. If possible, please also include an example of how to get the values out of whatever type you suggest.
I use System.Collections.ArrayList for this and you can then iterate through it using a For Each.
I don't know what you are using to deserialize your JSON but I use JavaScriptSerializer, E.g...
Imports System.Collections
Imports System.Collections.Generic
Imports System.Web.Script.Serialization
and then...
Dim sJSON as String = "{}" 'Contains the JSON in your question
Dim jsSerializer As JavaScriptSerializer = New JavaScriptSerializer()
Dim dictData As Dictionary(Of String, Object) = jsSerializer.Deserialize(Of Dictionary(Of String, Object))(sJSON)
If dictData.ContainsKey("c") Then
If TypeOf dictData("c") Is ArrayList Then
Dim arrData As ArrayList = DirectCast(dictData("c"), ArrayList)
For Each arrDataRecord In arrData
Next
End If
End If