I have a problem to get out nested Values from JSON Objects. I Googled and came up with a small solution that delivers the "root" or let's say "unnested" values. The Deserialisation doesn't parse out the nested values. And now I am stuck.
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
JSON File Source (s):
{
"matchNumber": "222",
"phase": "Bronze Medal Match",
"category": {
"name": "F-67kg",
"gender": "FEMALE",
"subCategory": "OLYMPIC CATEGORY",
"bodyLevel": 22,
"headLevel": 5
},
"blueAthlete": {
"name": "playernameblue",
"wtfId": "wtfidblue",
"flagAbbreviation": "GER"
},
"blueAthleteVideoQuota": 1,
"redAthlete": {
"name": "playernamered",
"wtfId": "wtfidred",
"flagAbbreviation": "AZE"
},
"redAthleteVideoQuota": 1,
"roundsConfig": {
"rounds": 3,
"roundTimeMinutes": 2,
"roundTimeSeconds": 0,
"kyeShiTimeMinutes": 1,
"kyeShiTimeSeconds": 0,
"restTimeMinutes": 1,
"restTimeSeconds": 0,
"goldenPointEnabled": true,
"goldenPointTimeMinutes": 1,
"goldenPointTimeSeconds": 0
},
"differencialScore": 20,
"maxAllowedGamJeoms": 0,
"paraTkdMatch": false
}
Generated VB Code and Classes out of this JSON:
Public Class Category
Public Property name As String
Public Property gender As String
Public Property subCategory As String
Public Property bodyLevel As String
Public Property headLevel As String
End Class
Public Class BlueAthlete
Public Property name As String
Public Property wtfId As String
Public Property flagAbbreviation As String
End Class
Public Class RedAthlete
Public Property name As String
Public Property wtfId As String
Public Property flagAbbreviation As String
End Class
Public Class RoundsConfig
Public Property rounds As Integer
Public Property roundTimeMinutes As Integer
Public Property roundTimeSeconds As Integer
Public Property kyeShiTimeMinutes As Integer
Public Property kyeShiTimeSeconds As Integer
Public Property restTimeMinutes As Integer
Public Property restTimeSeconds As Integer
Public Property goldenPointEnabled As Boolean
Public Property goldenPointTimeMinutes As Integer
Public Property goldenPointTimeSeconds As Integer
End Class
Public Class RootObject
Public Property matchNumber As String
Public Property phase As String
Public Property category As Category
Public Property blueAthlete As BlueAthlete
Public Property blueAthleteVideoQuota As Integer
Public Property redAthlete As RedAthlete
Public Property redAthleteVideoQuota As Integer
Public Property roundsConfig As RoundsConfig
Public Property differencialScore As Integer
Public Property maxAllowedGamJeoms As Integer
Public Property paraTkdMatch As Boolean
End Class
The Code I tried to Parse out the Values:
Dim rootObject As RootObject = JsonConvert.DeserializeObject(Of RootObject)(s)
String.Text = rootObject.matchNumber
String.Text = String.Text & vbCrLf & rootObject.phase
String.Text = String.Text & vbCrLf & rootObject.category.name
String.Text = String.Text & vbCrLf & rootObject.category.gender
String.Text = String.Text & vbCrLf & rootObject.category.subCategory
String.Text = String.Text & vbCrLf & rootObject.category.bodyLevel
String.Text = String.Text & vbCrLf & rootObject.category.headLevel
String.Text = String.Text & vbCrLf & rootObject.blueAthleteVideoQuota
String.Text = String.Text & vbCrLf & rootObject.redAthleteVideoQuota
String.Text = String.Text & vbCrLf & rootObject.differencialScore
String.Text = String.Text & vbCrLf & rootObject.maxAllowedGamJeoms
String.Text = String.Text & vbCrLf & rootObject.paraTkdMatch
The code returns matchNumber 222 and then a System.NullReferenceException occurs. Object not set to instance of Object
This row throws out the exception: String.Text = String.Text & vbCrLf & rootObject.category.name
in general all deeper nested values return that exception.
So the questions is, how to fix that?
Update: Here is the complete code for reproducing - So basicly this code is a simple server, retreiving the JSON data via a POST request. VAR jsonstring (renamed from s to jsonstring) contains the received JSON. Richtextbox1 also contains the JSON just for viewing that there is a JSON recieved. Richtextbox2 is for rowing up the values.
Imports System.Threading
Imports System.Net
Imports System.Text
Imports System.IO
Imports System
Imports System.Web
Imports System.Collections.Generic
Imports System.Threading.Tasks
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
Imports Newtonsoft.Json.Converters
Imports Newtonsoft.Json.Serialization
Public Class Server
#Region "VARS"
Private listener As HttpListener
Private mainThread As Thread
Dim encoding As New UTF8Encoding
Public Shared JSON_Route As String = ""
Dim jsonstring As String = ""
#End Region
Protected Overrides Sub OnFormClosing(ByVal e As System.Windows.Forms.FormClosingEventArgs)
listener.Abort()
mainThread.Join()
End Sub
Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
mainThread = New Thread(AddressOf mainRequestLoop)
mainThread.Start()
End Sub
Private Delegate Sub updateListBoxHandler(ByVal msg As String)
Public Sub UpdateListBox(ByVal msg As String)
If InvokeRequired Then
Invoke(New updateListBoxHandler(AddressOf UpdateListBox), New String() {msg})
Else
ListBox1.Items.Add(msg)
End If
End Sub
Public Class Category
Public Property name As String
Public Property gender As String
Public Property subCategory As String
Public Property bodyLevel As String
Public Property headLevel As String
End Class
Public Class BlueAthlete
Public Property name As String
Public Property wtfId As String
Public Property flagAbbreviation As String
End Class
Public Class RedAthlete
Public Property name As String
Public Property wtfId As String
Public Property flagAbbreviation As String
End Class
Public Class RoundsConfig
Public Property rounds As Integer
Public Property roundTimeMinutes As Integer
Public Property roundTimeSeconds As Integer
Public Property kyeShiTimeMinutes As Integer
Public Property kyeShiTimeSeconds As Integer
Public Property restTimeMinutes As Integer
Public Property restTimeSeconds As Integer
Public Property goldenPointEnabled As Boolean
Public Property goldenPointTimeMinutes As Integer
Public Property goldenPointTimeSeconds As Integer
End Class
Public Class RootObject
Public Property matchNumber As String
Public Property phase As String
Public Property category As Category
Public Property blueAthlete As BlueAthlete
Public Property blueAthleteVideoQuota As Integer
Public Property redAthlete As RedAthlete
Public Property redAthleteVideoQuota As Integer
Public Property roundsConfig As RoundsConfig
Public Property differencialScore As Integer
Public Property maxAllowedGamJeoms As Integer
Public Property paraTkdMatch As Boolean
End Class
Public Sub mainRequestLoop()
listener = New HttpListener()
listener.Prefixes.Add("http://localhost:" & TextBox_Port.Text & "/" & TextBox_Restfulpath.Text & "/")
Try
listener.Start()
Catch ex As Exception
MsgBox("Please start as Admin (with administration rights granted.)")
End Try
Try
Do
Dim ctx As HttpListenerContext = listener.GetContext()
Dim worker As New HttpRequestWorker(ctx, Me)
' ToDo: use threadpool threads probably better
Dim t As New Thread(AddressOf worker.ProcessRequest)
Dim request = ctx.Request
Dim body As Stream = request.InputStream
Dim reader As New StreamReader(body, encoding)
jsonstring = reader.ReadToEnd()
Richtextbox1.Text = jsonstring
Dim rootObject As RootObject = JsonConvert.DeserializeObject(Of RootObject)(s)
RichTextBox2.Text = rootObject.matchNumber
RichTextBox2.Text = RichTextBox2.Text & vbCrLf & rootObject.phase
RichTextBox2.Text = RichTextBox2.Text & vbCrLf & rootObject.category.name
RichTextBox2.Text = RichTextBox2.Text & vbCrLf & rootObject.category.gender
RichTextBox2.Text = RichTextBox2.Text & vbCrLf & rootObject.category.subCategory
RichTextBox2.Text = RichTextBox2.Text & vbCrLf & rootObject.category.bodyLevel
RichTextBox2.Text = RichTextBox2.Text & vbCrLf & rootObject.category.headLevel
RichTextBox2.Text = RichTextBox2.Text & vbCrLf & rootObject.blueAthleteVideoQuota
RichTextBox2.Text = RichTextBox2.Text & vbCrLf & rootObject.redAthleteVideoQuota
RichTextBox2.Text = RichTextBox2.Text & vbCrLf & rootObject.differencialScore
RichTextBox2.Text = RichTextBox2.Text & vbCrLf & rootObject.maxAllowedGamJeoms
RichTextBox2.Text = RichTextBox2.Text & vbCrLf & rootObject.paraTkdMatch
t.Start()
Loop
Catch ex As Exception
MsgBox(ex.ToString())
End Try
End Sub
' Http Request Handler
Private Class HttpRequestWorker
Private context As HttpListenerContext
Private caller As Server
Public Sub New(ByVal context As HttpListenerContext, ByVal f As Server)
Me.context = context
caller = f
End Sub
' Handle the request
Public Sub ProcessRequest()
Dim msg As String = context.Request.HttpMethod & " " & context.Request.Url.ToString()
JSON_Route = context.Request.Url.ToString()
caller.UpdateListBox(msg)
Dim url As System.Uri = context.Request.Url
Dim path As String = url.GetComponents(UriComponents.Path, UriFormat.SafeUnescaped)
Debug.WriteLine(path)
Dim response As HttpListenerResponse = context.Response
Try
Dim requestError As Boolean
Dim requestError1 As Boolean
requestError = context.Request.HttpMethod.ToUpper() <> "GET" OrElse String.IsNullOrEmpty(path)
requestError1 = context.Request.HttpMethod.ToUpper() <> "POST" OrElse String.IsNullOrEmpty(path)
If Not requestError Then
response.AddHeader("Cache-Control", "no-cache")
response.AddHeader("Pragma", "no-cache")
response.StatusCode = 200
Dim encoding As New UTF8Encoding
response.ContentEncoding = encoding
response.ContentType = "text/html"
Dim responseHtml As String = "Available"
Dim responseHtmlBytes() As Byte = encoding.GetBytes(responseHtml)
response.ContentLength64 = responseHtmlBytes.Length
Dim stream As IO.Stream = response.OutputStream
stream.Write(responseHtmlBytes, 0, responseHtmlBytes.Length)
stream.Close()
Else
response.StatusCode = 404
End If
Catch ex As Exception
response.StatusCode = 500
Finally
response.Close()
End Try
End Sub
End Class