Search code examples
c#castingjson-deserializationdefinition

C# dynamic anonymous JSON definition


I have a rather large JSON file I am attempting to parse and set definitions for in C#. I am getting an error from the Newtonsoft JSON Deserializer.

Newtonsoft.Json.JsonSerializationException: 'Error converting value 151 to type 'QA_Test1.json.states'. Path 'MyFlow.states[1]', line 8378, position 15.'

-       InnerException  {"Could not cast or convert from System.Int64 to QA_Test1.json.states."}    System.Exception {System.ArgumentException}

Because this element is an array [] and has a nested list, side by side with anonymous integers. I'm stuck here

"states": [
  { .. some more json data 
  },
  12,
  14,
  9,
  10
]

The first problem (1) I don't even need the integer data, I need the nested data but the Newtonsoft Deserializer is still trying to deserialize the integer data without a def.

The second problem (2) The "variables" element has anonymous elements also, I want to get the names example anonomousVarName1 and get the properties of that item. But I wont know what they are. So having a definition I am finding difficult.

"states": [
  { .. some more json data 
  },
  12, // problem 1
  14,
  9,
  10
],
"variables": {
        "anonomousVarName1": {
            "blah": ".VariableImpl",
            "blah": 407
            },
            "blah": false,
            "blah": null
        },
        "anonomousVarName2": {
            {
            "blah": ".VariableImpl",
            "blah": 407
            },
            "blah": false,
            "blah": null
            }
        }

My definition

public class state_connections
{
    [JsonProperty("states")]
    public List<states> states { get; set; }

    [JsonProperty("variables")]
    public Dictionary<string, variables> variables { get; set; } // added resolution for problem 2
}

Problem #1 remains a huge issue problem #2 is resolved by using

Dictionary<string, variables> variables {get; set;}

Accessing the Dictionary variables

connections_def file = JsonConvert.DeserializeObject<connections_def>(_data_file, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All, MaxDepth = 200, NullValueHandling = NullValueHandling.Ignore });
           
            foreach(var variable in file.automatonFlow.variables)
            {
                Console.WriteLine();
                Console.WriteLine($"Variable Key Name: {variable.Key}");
                Console.WriteLine("--- properties ---");
                Console.WriteLine($"    @class: {variable.Value.@class}");
                Console.WriteLine($"    @id: {variable.Value.id}");
                Console.WriteLine($"    defaultValue: {variable.Value.defaultValue}");
                Console.WriteLine($"    id: {variable.Value.long_id}");
                Console.WriteLine($"    name: {variable.Value.name}");
                Console.WriteLine($"    notes: {variable.Value.notes}");
                Console.WriteLine($"    secure: {variable.Value.secure}");
                Console.WriteLine($"    stateId: {variable.Value.stateId}");
                Console.WriteLine($"    type: {variable.Value.type}");
            }

Solution

  • Thank you Rivo for your assistance as clearly this could not be done without implementing List object. Still open to suggestions but here is what I found as a work-around and this is by far, a hack for a horribly designed JSON.

            foreach(var state in file.automatonFlow.states)
            {
                //check if object is actually the json I want and not the stupid integers
                if (state.GetType() == typeof(Newtonsoft.Json.Linq.JObject))
                {
                    Console.WriteLine("--- states ---");
    
                    //convert the object BACK into text
                    var jobject = (JsonConvert.SerializeObject(state));
    
                    //convert the data BACK into definition form
                    states states = JsonConvert.DeserializeObject<states>(jobject, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All, MaxDepth = 200, NullValueHandling = NullValueHandling.Ignore });
    
                    Console.WriteLine($"    @id: {states.id}");
                    Console.WriteLine($"    actionClass: {states.actionClass}");
                    Console.WriteLine($"    name: {states.name}");
                    Console.WriteLine();
                }   
            }
            Console.ReadLine();
    

    Definition

     public class connections_def
    {
        [JsonProperty("states")]
        public List<object> states  { get; set; }
    
        [JsonProperty("variables")]
        public Dictionary<string, variables> variables { get; set; }
    }
    

    ---Outputs----

    --- states ---
    
    @id: 1
    actionClass: HostCommandAction
    name: Check Service running