1

I'm trying to convert the following JSON example to a vb.net Class or just plain read the information. I can get the first parts, ID, name and objCode, but I can't parse out the parameterValues because the column names have spaces. So I can't assign a class field name as [DE:App code]. This is coming from a custom template so the field names can be called anything. I need to loop through all the parameterValues and get the name and value so I can add them to a database. The main values I need (that will always be there) are ID, DE:App Code and DE:App Alloc 1 Code.

{
  "data": [
    {
      "ID": 43545325253,
      "name": "FY1955: PAT",
      "objCode": "PROJ",
      "parameterValues": {
        "DE:": "PS12",
        "DE:Please Enter Requested": "/rss55.edu",
        "DE:URL Allocation 1": "Society Scholarship",
        "DE:Is this being created for other purposes?": "no",
        "DE:Request Submitted by": "urser55",
        "DE:Project Owner": "Admin User",
        "DE:App Code": "YDAR",
        "DE:App Completion Date": "2018-12-14",
        "DE:App Alloc 1 Code": "SBDRC"
      }
    }
  ]
}

Does anyone have any ideas about how I can solve this? If you can provide any VB.Net example code, that would be great.


It seems that requirements have changed. They added another sub piece within the parameter which crashes my code on "DE:App Units". Here is what the JSON looks like now:

{
  "data": [
    {
      "ID": 43545325253,
      "name": "FY1955: PAT",
      "objCode": "PROJ",
      "parameterValues": {
        "DE:": "PS12",
        "DE:Please Enter Requested": "/rss55.edu",
        "DE:URL Allocation 1": "Society Scholarship",
        "DE:Is this being created for other purposes?": "no",
        "DE:Request Submitted by": "urser55",
        "DE:Project Owner": "Admin User",
        "DE:App Code": "YDAR",
        "DE:App Completion Date": "2018-12-14",
        "DE:App Units": [
          "University-Wide",
          "All Colleges"
        ],
        "DE:App 1 Long Name - 1": "Pref Univ",
        "DE:Mailing Components": [
          "Reply Envelope",
          "Outer Envelope",
          "Letter"
        ],
        "DE:App Alloc 1 Code": "ABBRC"
      }
    }
  ]
}

How can I get it to work with this new JSON?

3
  • You can use paste special in visual studio check this Commented Dec 13, 2018 at 21:07
  • That is not valid json... Commented Dec 13, 2018 at 21:39
  • Assuming you're using Newtonsoft for de-serialization you can set the properyname <JsonProperty(PropertyName:="DE:App Alloc 1 Code")> in the class properties. Commented Dec 13, 2018 at 22:26

1 Answer 1

1

Since your parameter names can be anything, I would suggest using a Dictionary(Of String, String) for that part. Declare your model classes like this:

Class RootObject
    Public Property Data As List(Of Item)
End Class

Class Item
    Public Property ID As String
    Public Property Name As String
    Public Property ObjCode As String
    Public Property ParameterValues As Dictionary(Of String, String)
End Class

Using a decent JSON library like Json.Net, you can deserialize the JSON into these models easily:

Dim root As RootObject = JsonConvert.DeserializeObject(Of RootObject)(json)

From there you can use the models like you would for any other class. For example, here is how you would dump out all the data to the console:

For Each item In root.Data
    Console.WriteLine("ID: " & item.ID)
    Console.WriteLine("Name: " & item.Name)
    Console.WriteLine("ObjCode: " & item.ObjCode)
    Console.WriteLine()

    Console.WriteLine(String.Format("{0,-45} {1}", "Parameter Name", "Parameter Value"))
    Console.WriteLine(New String("-", 45) & " " & New String("-", 20))

    For Each kvp In item.ParameterValues
        Console.WriteLine(String.Format("{0,-45} {1}", kvp.Key, kvp.Value))
    Next
Next

Working demo: https://dotnetfiddle.net/SqInI6


To address your updates:

It looks like your each of your parameter values can now be a either single string or an array of strings. This will crash the current code because the dictionary can only hold simple string values. You could change your dictionary declaration to Dictionary(Of String, Object) and that will allow it to deserialize, but if you do that you will end up with a mix of strings and JArrays in your dictionary. You will then need to check the type of value everywhere you use it and handle it appropriately, e.g.:

If kvp.Value Is GetType(JArray) Then
    Dim list As List(Of String) = DirectCast(kvp.Value, JArray).ToObject(Of List(Of String))
    ... handle multiple values ...
Else
    Dim str As String = DirectCast(kvp.Value, String)
    ... handle single value ...
End If

I think a better solution is to change your dictionary be a Dictionary(Of String, List(Of String)), and then use a custom JsonConverter to populate it from the JSON. That will allow you to handle the values uniformly in the rest of your code, because you know you will always have a list of strings.

If you went with that approach, you would need the following converter:

Public Class SingleOrArrayDictionaryConverter(Of T)
    Inherits JsonConverter

    Public Overrides Function CanConvert(objectType As Type) As Boolean
        Return objectType = GetType(Dictionary(Of String, List(Of T)))
    End Function

    Public Overrides Function ReadJson(reader As JsonReader, objectType As Type, existingValue As Object, serializer As JsonSerializer) As Object
        Dim obj = JObject.Load(reader)
        Dim dict = New Dictionary(Of String, List(Of T))
        For Each prop In obj.Properties()
            If prop.Value.Type = JTokenType.Array Then
                dict.Add(prop.Name, prop.Value.ToObject(Of List(Of T)))
            Else
                dict.Add(prop.Name, New List(Of T) From {prop.Value.ToObject(Of T)})
            End If
        Next
        Return dict
    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

To use the converter, add a <JsonConverter> attribute to your ParameterValues property like this:

    <JsonConverter(GetType(SingleOrArrayDictionaryConverter(Of String)))>
    Public Property ParameterValues As Dictionary(Of String, List(Of String))

Demo: https://dotnetfiddle.net/oA3bfE

Sign up to request clarification or add additional context in comments.

2 Comments

brian, they added another sub piece within the param. which crashes my code on "DE:App Units" example: "DE:App Completion Date": "2018-12-14", "DE:App Units": [ "University-Wide", "All Colleges" ], "DE:App 1 Long Name - 1": "Pref Univ",
your solution works great! sorry for posting as answer. it just wouldn't let me post the new code into a comment because of the length. thanks again.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.