1

I have a bunch of JSON objects that I'm reading in via REST. They follow a format like this:

{
    "Id": 13,
    "ParentId": 21,
    "Description": "This is the description"
    "Errors": []
}

I'm creating a class from the returned JSON object. In this example, the class would look like this:

Public Class ReturnedInfo
    Public Id As Integer
    Public ParentId As Integer
    Public Description As String
    Public Errors As ErrorDetail()
End Class

Then I'm pulling in the data like this:

Private Function GetReturnedInfo(myID As Integer, tkn As String) As ReturnedInfo
    Dim rval As ReturnedInfo = New ReturnedInfo()

    Try
        'set up request
        Dim url As String = "https://www.exampleurl.com"
        Dim request As HttpWebRequest = CType(WebRequest.Create(url), HttpWebRequest)
        request.Method = "POST"
        request.ContentType = "application/json"

        'add logon data to the request stream
        Dim dataStream As Stream = request.GetRequestStream()
        Using writer As New StreamWriter(dataStream)
            writer.Write("{""Username"":""MyUserName"", ""Company"":""1234-56789-123"",""SecurityToken"":""" + tkn + """, ""ID"":""" + myID + """}")
        End Using
        dataStream.Close()

        'run the request and collect the response
        Dim ws As WebResponse = request.GetResponse()
        Dim rs As System.IO.Stream = ws.GetResponseStream()

        Dim jsonString As String = String.Empty
        Using sreader As System.IO.StreamReader = New System.IO.StreamReader(rs)
            jsonString = sreader.ReadToEnd()
        End Using

        'pull data from the response and convert it to a ReturnedInfo
        Dim jsSerializer As System.Web.Script.Serialization.JavaScriptSerializer = New System.Web.Script.Serialization.JavaScriptSerializer()
        Dim retInfo As ReturnedInfo = jsSerializer.Deserialize(Of ReturnedInfo)(jsonString)

        'If the security token is expired, get a new one and re-call function
        If retInfo.Errors.Length > 0 Then
            If retInfo.Errors(0).Code = "Validation Error" Then
                token = GetSecurityToken()
                rval = GetReturnedInfo(myID, token.SecurityToken)
            End If
        Else
            rval = retInfo
        End If

    Catch wex As WebException
        'exceptions from the server are communicated with a 4xx status code
        Dim errorMsg As String = HandleWebException(wex)
        Throw New System.Exception(errorMsg)
    Catch ex As Exception
        'TODO: open dialog box and display ex
        Throw New System.Exception("Hit exception: " & ex.Message)
    End Try

    Return rval
End Function

This logic has worked perfectly for me until I ran into a returned JSON object that looks like this:

{
    "$id": 10
    "Id": 13,
    "ParentId": 21,
    "Description": "This is the description"
    "Errors": []
}

Since VB.NET won't let me declare a variable that starts with a $ I'm kind of stuck. How do I either force VB.NET to like the $ or find another way around this?

Thanks!

TheIronCheek
  • 1,077
  • 2
  • 20
  • 50
  • 1
    Have you tried [data contract](http://stackoverflow.com/a/1109605/130611)? – the_lotus Sep 08 '15 at 13:37
  • @the_lotus - I haven't. I'll give it a try. I'm currently looking for a VB.NET implementation as the link you referenced is in C#. I'm not 100% sure on the syntax difference. – TheIronCheek Sep 08 '15 at 13:58
  • 1
    There's not a big difference between [C# and VB.NET property attributes](https://msdn.microsoft.com/en-us/library/z0w1kczw.aspx?cs-save-lang=1&cs-lang=vb#code-snippet-1). – the_lotus Sep 08 '15 at 14:35

1 Answers1

2

Use the DataMember attribute to indicate the name in the json (I changed all the propnames in the json to demonstrate):

<DataContract>
Public Class ReturnedInfo
    <DataMember(Name:="$Id")>
    Public Property Id As Integer
    <DataMember(Name:="$Parent")> 
    Public Property ParentId As Integer
    <DataMember(Name:="$Descr")> 
    Public Property Description As String
    <DataMember(Name:="$Errors")> 
    Public Property Errors As String()

    Public Sub New()

    End Sub

End Class

I also do not know what ErrorDetail looked like, so I made it a simple array. Deserializing is different:

Imports System.Runtime.Serialization.Json

Dim jstr = ...from whereever
Dim ser As New DataContractJsonSerializer(GetType(ReturnedInfo))

Using ms As New MemoryStream(UnicodeEncoding.UTF8.GetBytes(jstr))
    Dim result As ReturnedInfo = CType(ser.ReadObject(ms), ReturnedInfo)
    Console.WriteLine("Id: {0}, Error(0): {1}", result.Id, result.Errors(0))
End Using

Id: 13, Error(0): hello world

Personally, I think that is too much bother. Newtonsoft is easier:

Public Class ReturnedInfo
    <JsonProperty("$Id")>
    Public Property Id As Integer
    ' etc

Deserialize:

Dim jstr = ...from whereever
Dim rinfo = JsonConvert.DeserializeObject(Of ReturnedInfo)(jstr)

Console.WriteLine("(Newtonsoft) Id: {0}, Error(0): {1}", rinfo.Id, rinfo.Errors(0))

(Newtonsoft) Id: 13, Error(0): hello world

Ňɏssa Pøngjǣrdenlarp
  • 38,411
  • 12
  • 59
  • 178