Deserialize Application Insights Analytics with Json.net - json

I'm trying to use Json.net to deserialize JSON from Application Insights Analytics (AIA) into my class. I'm not sure if I'm approaching it right, but I use LINQ-to-JSON to get at the data section of the JSON and then try to deserialize to my class using this code:
Dim rawjson As String = GetTelemetry()
Dim o As JObject = JObject.Parse(rawjson)
Dim ds = DirectCast(o("Tables")(0)("Rows"), JArray)
Dim Sessions As List(Of Session) = JsonConvert.DeserializeObject(Of List(Of Session))(ds)
This fails as the JSON from AIA is in this format:
"Rows": [
[
"Boy",
"9",
"",
"",
"0",
"0",
"22",
"0"
],
[
"Boy",
"9",
"",
"",
"0",
"0",
"41",
"0"
],
Notice the data for the individual rows is an array rather than an object.
My Session class is defined like this:
Public Class Session
Public Property Gender As String
Public Property Age As Integer
Public Property SessionVids As Integer
Public Property TotalVids As Integer
Public Property ChildUse As Integer
Public Property ChildTime As Integer
Public Property AdultUse As Integer
Public Property AdultTime
End Class
Can someone please explain how to do this?

You can convert the JArray of rows (ds) into a list of Session objects like this:
Dim Sessions As List(Of Session) =
ds.Select(Function(ja)
Dim s As New Session()
s.Gender = ja(0).Value(Of String)()
s.Age = GetInt(ja(1))
s.SessionVids = GetInt(ja(2))
s.TotalVids = GetInt(ja(3))
s.ChildUse = GetInt(ja(4))
s.ChildTime = GetInt(ja(5))
s.AdultUse = GetInt(ja(6))
s.AdultTime = GetInt(ja(7))
Return s
End Function).ToList()
where GetInt is a helper function defined like this:
Public Function GetInt(jt As JToken) As Integer
Dim i As Integer
If Integer.TryParse(jt.Value(Of String)(), i)
Return i
End If
Return 0
End Function
The helper function is needed since the JSON has empty strings for some of the values while your class requires valid integers.
Fiddle: https://dotnetfiddle.net/GqFcov

Related

How to deserialize a List(Of Object) from JSON?

I have a List(Of Object) that I am using in a property of type IEnumerable(Of Object). I can serialize it fine but cannot work out then how to deserialize it from JSON back to a List(Of Object). Any help would be really great please.
My ViewModel:
Public Class ViewModel
Inherits ViewModelBase
Public Class MapSettings
<Display(Name:="Map Name", Description:="Enter a optional name for the map.", GroupName:="Map Settings")>
Public Property MapName As String
<Display(Name:="Map Description", Description:="Enter a optional description for the map.", GroupName:="Map Settings")>
Public Property MapDescription As String
<Display(Name:="Map Comments", Description:="Enter optional comments for the map.", GroupName:="Map Settings")>
Public Property MapComments As String
<Display(Name:="Map Version", Description:="Enter a optional version for the map.", GroupName:="Map Settings")>
Public Property MapVersion As String
End Class
Public Class GeneralSettings
<Display(Name:="Route Colour", Description:="Sets the colour of the routes design line on the map.", GroupName:="General Settings")>
Public Property Foreground As Color
End Class
Private _myItems() As IEnumerable(Of Object)
Public Property MyItems() As IEnumerable(Of Object)
Get
If _myItems Is Nothing Then
Return New List(Of Object)() From {
New MapSettings,
New GeneralSettings With {.Foreground = Colors.Blue}
}
Else
Return _myItems
End If
End Get
Set(value As IEnumerable(Of Object))
_myItems = value
OnPropertyChanged()
End Set
End Property
End Class
My serialize code that I cannot complete:
Dim MyItems_New = JsonConvert.DeserializeObject(Of MyItems???)(MyJsonString)
JSON:
{
"MyItems": [
{
"MapName": null,
"MapDescription": null,
"MapComments": null,
"MapVersion": null
},
{
"Foreground": "#FF0000FF"
}
]
}
I just found that Newtonsoft has built-in support for type handling, which can be enabled by setting the JsonSerializerSettings.TypeNameHandling property and passing it to the serialization methods. As long as you control the input, this should let you both serialize and deserialize your list without a problem.
Serialize:
Dim myItems = JsonConvert.SerializeObject(myVM.MyItems, Formatting.None, New JsonSerializerSettings() With { .TypeNameHandling = TypeNameHandling.Auto })
Deserialize:
Dim myItems_New = JsonConvert.DeserializeObject(Of List(Of Object))(MyJsonString, New JsonSerializerSettings() With { .TypeNameHandling = TypeNameHandling.Auto })
In your question, MyJsonString appears to be a serialized version of your ViewModel class rather than just the list itself. If this is the case, change DeserializeObject(Of List(Of Object)) to DeserializeObject(Of ViewModel).
Resulting JSON:
[
{
"$type": "MapSettings, YourProjectNamespace",
"MapName": "New York",
"MapDescription": "Map over New York",
"MapComments": null,
"MapVersion": "v1"
},
{
"$type": "GeneralSettings, YourProjectNamespace",
"Foreground": "#FF0000"
}
]
Try it online (C#):
https://dotnetfiddle.net/0jCIGL
However, if these two classes are all you are planning to use this list for, then you'd be better off using something along the lines of Jimi's proposed solution, as then you're always working with strongly-typed objects.

how to filter a specific part of a json string

ive been working on json for about 2 days and its all new to me so im learning as i go i have this string im working with
{
"elements": [{
"id": "123",
"hidden": false,
"name": "testname",
"sku": "1234",
"price": 2499,
"priceType": "FIXED",
"defaultTaxRates": true,
"cost": 1299,
"isRevenue": true,
"stockCount": 0,
"itemStock": {
"item": {
"id": "123"
},
"stockCount": 3,
"quantity": 3.0
},
"modifiedTime": 1504112254000
}],
"href": "http://api.server.com/items"
}
i am usnig the Newtonsoft.Json library
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
Imports System.Net
Imports System.IO
Public Class Form1
Dim token = ""
Dim url = "https://api.Server.com/"
Dim mid = ""
Dim parm1 = ""
Dim parm2 = ""
Dim parm3 = ""
Dim parm = parm1 & parm2 & parm3
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim jsonURL As String = url & mid & "/items?" & parm
Dim reader As StreamReader
Dim errorMsg As String = Nothing
Try
Dim request As HttpWebRequest = CType(WebRequest.Create(jsonURL), HttpWebRequest)
request.Headers.Add("Authorization", "Bearer " + token)
Dim response As HttpWebResponse = CType(request.GetResponse(), HttpWebResponse)
reader = New StreamReader(response.GetResponseStream())
Dim jsonStr As String = reader.ReadToEnd()
Dim JsonObject As JObject = JObject.Parse(jsonStr)
Dim jsonArray As JArray = JArray.Parse(JsonObject.SelectToken("elements").ToString)
For Each items As JObject In jsonArray
Dim product As item = JsonConvert.DeserializeObject(Of item)(items.ToString)
idTxtbox.Text = product.id
hiddenTxtbox.Text = product.hidden
nameTxtbox.Text = product.name
skuTxtbox.Text = product.sku
priceTxtbox.Text = product.price
priceTypeTxtbox.Text = product.priceType
defaultTaxRatesTxtbox.Text = product.defaultTaxRates
CostTxtbox.Text = product.cost
isRevenueTxtbox.Text = product.isRevenue
stockCountTxtbox.Text = product.stockCount
For Each itema In product.itemStock
ListBox1.Items.Add(itema("itemStock"))
Next
modifiedTimeTxtbox.Text = product.modifiedTime
MsgBox("")
Next
Catch ex As WebException
errorMsg = "Download failed. The response from the server was: " +
CType(ex.Response, HttpWebResponse).StatusDescription
Console.WriteLine("Error: " + errorMsg)
End Try
End Sub
End Class
Class item
Public id As String
Public hidden As String
Public name As String
Public sku As String
Public price As String
Public priceType As String
Public defaultTaxRates As String
Public cost As String
Public isRevenue As String
Public stockCount As String
'Public itemStock As Dictionary(Of String, String) = New Dictionary(Of String, String)
'Public itemStock As List(Of String) = New List(Of String)
Public Property itemStock() As IList(Of String)
Get
Return m_itemStock
End Get
Set(ByVal value As IList(Of String))
m_itemStock = value
End Set
End Property
Private m_itemStock As IList(Of String)
Public modifiedTime As String
End Class
i can get all the values of the first group of data but cant seems the "stockCount": 3 to show up any idea how i can phrase this?
sorry if im not super clear if you need more info i will try to provide it
i have updated the code of what i have so far i have gotten the JsonConvert.DeserializeObject to work but still cant seem to get the values of
"itemStock": {
"item": {
"id": "123"
},
"stockCount": 3,
"quantity": 3.0
},
to populate in listbox1.items
i receive this error
Cannot deserialize the current JSON object (e.g. {"name":"value"})
into type 'System.Collections.Generic.IList`1[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

VB.NET Json Parse

I'm trying to process the JSON input below. The code (bottom) throws
Error reading JObject from JsonReader.
Current JsonReader item is not an object: StartArray.
Path '', line 1, position 1.
Input:
[
{
"data": [
{
"photos": {
"data": [
{
"id": "1",
"name": "test Post",
"images": [
{
"height": 1024,
"source": "https://127.0.0.1:8080/image1.png",
"width": 1204
},
{
"height": 1204,
"source": "https://127.0.0.1:8080/image2.png",
"width": 1204
}
],
}
]
}
}
}
Code:
Dim ser As JObject = JObject.Parse(result.ToString)
Dim data As List(Of JToken) = ser.Children().ToList
Dim jsonString As String = Nothing
Dim index As Integer = 0
For Each item As JProperty In data
item.CreateReader()
Select Case item.Name
Case "data"
jsonString = item.Value.ToString
End Select
Next
ser = JObject.Parse(jsonString)
data = ser.Children().ToList
For Each item As JProperty In data
item.CreateReader()
Select Case item.Name
Case "photos"
jsonString = item.Value.ToString
End Select
Next
ser = JObject.Parse(jsonString)
data = ser.Children().ToList
For Each item As JProperty In data
item.CreateReader()
Select Case item.Name
Case "data"
For Each comment As JObject In item.Values
Dim _id As String = comment("id")
Dim _title As String = comment("title")
Dim _name As String = comment("name")
Dim _source As String = comment("source")
Dim source As List(Of JToken) = item.Value.ToList
For Each images As JProperty In source
item.CreateReader()
Select Case item.Name
Case "images"
Dim _tempsource As String = source("source")
_source += _tempsource & vbCrLf
End Select
Next
Dim _created_time As String = comment("created_time")
Dim itm As New ListViewItem(_id, 1)
itm.SubItems.Add(_title)
itm.SubItems.Add(_name)
itm.SubItems.Add(_source)
itm.SubItems.Add(_created_time)
lvItems.Items.AddRange(New ListViewItem() {itm})
index += 1
Next
End Select
Next
I access this namespace with
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
What am I doing wrong?
I used JSONLint to debug your JSON, because it is not valid. you must check whether your source is sending you invalid JSON, or there was a typo when posting it here. This would be valid JSON:
[{
"data": [{
"photos": {
"data": [{
"id": "1",
"name": "test Post",
"images": [{
"height": 1024,
"source": "https://127.0.0.1:8080/image1.png",
"width": 1204
}, {
"height": 1204,
"source": "https://127.0.0.1:8080/image2.png",
"width": 1204
}]
}]
}
}]
}]
Then, You can use a tool like JSON Utils or VS itself (copying JSON to the clipboard and using Edit > Paste Special > Paste JSON as Classes) to generate VB classes that match JSON structure:
Public Class Image
Public Property height As Integer
Public Property source As String
Public Property width As Integer
End Class
Public Class PhotoDatum
Public Property id As String
Public Property name As String
Public Property images As Image()
End Class
Public Class Photos
Public Property data As PhotoDatum()
End Class
Public Class Datum
Public Property photos As Photos
End Class
Public Class SER
Public Property data As Datum()
End Class
Anyway, if you add the classes above to your project, you can just do this:
Dim MySER = JsonConvert.DeserializeObject(Of SER)(jsonString)
Dim itm As ListViewItem
Dim MyItems As New List(Of ListViewItem)
For Each d In MySER
If d.photos IsNot Nothing Then
For each dd in d.photos.data
If dd.images IsNot Nothing Then
For each img In dd.images
itm = New ListViewItem(dd.id, 1)
itm.SubItems.Add(dd.name)
itm.SubItems.Add(img.source)
MyItems.Add(itm)
Next
End If
Next
End If
Next
lvItems.Items.AddRange(MyItems)
And work with your structured objects.

JSON.net VB.net parse to get only colors from json return

Hey all I am trying to parse the following JSON in order to get the colors for the exterior:
{
"styles": [{
"make": {
"id": 200001444,
.....etc etc
},
"model": {
"id": "Honda_Pilot",
.....etc etc
},
"engine": {
"id": "200058127",
.....etc etc
"rpm": {
"horsepower": 5700,
"torque": 4800
},
"valve": {
"timing": "variable valve timing",
"gear": "single overhead camshaft"
}
},
"transmission": {
"id": "200058128",
.....etc etc
},
"drivenWheels": "four wheel drive",
.....etc etc
"colors": [{
"category": "Interior",
"options": [{
"id": "200058068",
"name": "Blue",
.....etc etc
}]
}, {
"category": "Exterior",
"options": [{
"id": "200058073",
"name": "Crystal Black Pearl",
.....etc etc
}
}, {
"id": "200058072",
"name": "Polished Metal Metallic",
.....etc etc
So far I have gotten to the "colors" but I am unable to get any further:
VB.net code:
Dim json2
Using httpClient = New HttpClient()
json2 = Await httpClient.GetStringAsync("URL HERE")
End Using
Dim rootObject2 = JObject.Parse(json2)
For Each token As JToken In rootObject2("styles")
Dim results As List(Of JToken) = token.Children().ToList
For Each item As JProperty In results
Select Case item.Name
Case "colors"
For Each subitem As JObject In item.Values
Dim tmp = subitem("category")
For Each subitem2 As JObject In tmp.Values
Dim tmp2 = subitem("category")
Next
Next
End Select
Next
Next
I am sure there's a simpler way of going about this but I just wanted to show that I did try to figure it out before coming here to get help on the code.
I am trying to loop through and get all Exterior colors by name.
Thanks!
I usually use a System.Web.Script.Serialization.JsonSerializer class instance.
In a Console (Module) Application, ensure you include System.Web.Extensions as a reference to your project...
Define your Models that will be used in the Deserilization process.
VB.NET
Module Module1
Sub Main()
Dim result = GetData()
End Sub
Public Class MakeStyle
Public Property Id As Integer
End Class
Public Class ModelStyle
Public Property Id As String
End Class
Public Class EngineStyle
Public Property Id As String
Public Property RotationsPerMinute As EngineRotationsPerMinuteStyle
End Class
Public Class EngineRotationsPerMinuteStyle
Public Property HorsePower As Integer
Public Property Torque As Integer
End Class
Public Class Payload
Public Property Make As MakeStyle
Public Property Model As ModelStyle
Public Property Engine As EngineStyle
Public Property Colors As IEnumerable(Of ColorStyle)
End Class
Public Class ColorStyleOptionItem
Public Property Id As String
Public Property Name As String
End Class
Public Class ColorStyle
Public Property Category As String
Public Property Options As IEnumerable(Of ColorStyleOptionItem)
End Class
Public Class DataItem
Public Property Category As String
Public Property Id As String
Public Property Name As String
End Class
Public Function GetData() As IEnumerable(Of DataItem)
Dim payloadString As String = GetDemoData() ' json serialized data
Dim serializer As System.Web.Script.Serialization.JavaScriptSerializer = New System.Web.Script.Serialization.JavaScriptSerializer()
Dim payload = serializer.Deserialize(Of Payload)(payloadString) ' sets Property Values of Payload to 'Nothing' when the json fields are not present in the json string.
Dim data As IEnumerable(Of DataItem) = payload.Colors.SelectMany(Function(item) item.Options.Select(Function(opt) New DataItem With {.Category = item.Category, .Id = opt.Id, .Name = opt.Name}))
GetData = data
End Function
Public Function GetDemoData() As String
Dim serializer As System.Web.Script.Serialization.JavaScriptSerializer = New System.Web.Script.Serialization.JavaScriptSerializer()
GetDemoData = serializer.Serialize(New Payload() With {
.Make = New MakeStyle() With {.Id = 200001444},
.Model = New ModelStyle() With {.Id = "Honda_Pilot"},
.Engine = New EngineStyle With {.Id = "200058127", .RotationsPerMinute = New EngineRotationsPerMinuteStyle() With {.HorsePower = 5700, .Torque = 4800}},
.Colors = New ColorStyle() {
New ColorStyle() With {
.Category = "Interior",
.Options = New ColorStyleOptionItem() {
New ColorStyleOptionItem() With {.Id = "200058068", .Name = "Blue"}
}
},
New ColorStyle() With {
.Category = "Exterior",
.Options = New ColorStyleOptionItem() {
New ColorStyleOptionItem() With {.Id = "200058073", .Name = "Crystal Black Pearl"},
New ColorStyleOptionItem() With {.Id = "200058072", .Name = "Polished Metal Metallic"}
}
}
}
})
End Function
End Module
I think you want something like this:
For Each style As JToken In rootObject2("styles")
Dim model As String = style.SelectToken("model.id").ToString()
Console.WriteLine("Exterior colors for " & model & ":")
For Each colorCategory As JToken In style("colors")
Dim categoryName As String = colorCategory("category").ToString()
If categoryName = "Exterior" Then
For Each opt As JToken In colorCategory("options")
Dim color as String = opt("name").ToString()
Console.WriteLine(" " & color)
Next
End If
Next
Next
Fiddle: https://dotnetfiddle.net/IVc2EC

Json deserialize list vs datatable (several cases)

I have the following json:
{
"Header": {
"MCC": "415",
"FO": "0",
"REGID": "5"
},
"Contacts": [
{
"NAME": "jocelyne",
"MO": "70123456"
},
{
"NAME": "eliane",
"MO": "03123456"
}
] }
I have 2 clients: one client is giving me this json in this order, the second is giving me the mo before name in the json, but I need to have the same order in the datatable all the time when I deserialize the json.
What I need to know which is the better way?
1-to deserialize the json in a list (it takes the tags in the alphabetic order) and then convert the list to a datatable
in this case that's what i'm doing:
Public Class Dataa
Public MCC As Integer
Public FO As Integer
Public RegId As Integer
Public Contacts As Contacts()
End Class
<Serializable()> _
Public Class Contacts
Public name As String
Public mo As String
End Class
Dim jss As New JavaScriptSerializer
Dim oFareResults As Generic.List(Of Dataa) = jss.Deserialize(Of List(Of Dataa))(json)
contactsDT = ConvertListToDataTable(oFareResults)
contactsDT.Columns.Add("taken_mo", GetType(String))
contactsDT.Columns.Add("reg_id", GetType(Integer))
Private Shared Function ConvertListToDataTable(oFareResults As List(Of Dataa)) As DataTable
' New table.
Dim dtTable As New DataTable()
dtTable.Columns.Add("name", GetType(String))
dtTable.Columns.Add("mo", GetType(String))
For i As Integer = 0 To oFareResults.Item(0).Contacts.Length - 1
dtTable.Rows.Add(oFareResults(0).Contacts(i).name, oFareResults(0).Contacts(i).mo)
Next
Return dtTable
End Function
2-to select 2 cases, every case for a different client and then deserialize the json in a datatable
in this case:
Public Class Data
Public Header As Header
Public Contacts As DataTable
End Class
<System.Runtime.Serialization.DataContract()>
Public Class Header
<System.Runtime.Serialization.DataMember(Name:="MCC")>
Public MCC As Integer
<System.Runtime.Serialization.DataMember(Name:="FO")>
Public FO As Integer
<System.Runtime.Serialization.DataMember(Name:="REGID")>
Public RegId As Integer
End Class
Dim data As New Data
data = JsonConvert.DeserializeObject(Of Data)(json)
mcc = data.Header.MCC
FO = data.Header.FO
regid = data.Header.RegId
contactsDT = data.Contacts
that's how i have to deserialize the json into a datatable and in this case i have to have 2 functions to deserialize one for every client ( to reserve the order that i need)
Well, what I need to know is not the general solution but I need to know which one has a better performance for the server considering that my json may be very long.
so i need the advantages and disadvantages of each case