Search code examples
c#json.netparsingjson.net

How to Deserialize complex JSON and create it as C# Object


I have a JSON which looks like as follows :

{
    "Values": [
        {
            "MsgSource": null,
            "TagName": "Data.New_MSG",
            "RawValue": "[\r\n  {\r\n    \"ID\": 145,\r\n    \"StationNo\": 6,\r\n    \"RunTime\": 1800,\r\n    \"ControllerID\": 4,\r\n    \"ControllerAddress\": 2,\r\n    \"ProgramNo\": 2,\r\n    \"ModeID\": \"AutoProgram\",\r\n    \"EventDate\": \"2022-04-27T23:30:02\",\r\n    \"Description\": \"Irrigation Completed\",\r\n    \"MessageCode\": 5\r\n  },\r\n  {\r\n    \"ID\": 144,\r\n    \"StationNo\": 18,\r\n    \"RunTime\": 1800,\r\n    \"ControllerID\": 4,\r\n    \"ControllerAddress\": 2,\r\n    \"ProgramNo\": 5,\r\n    \"ModeID\": \"AutoProgram\",\r\n    \"EventDate\": \"2022-04-27T22:00:00\",\r\n    \"Description\": \"Irrigation Completed\",\r\n    \"MessageCode\": 5\r\n  },\r\n  {\r\n    \"ID\": 143,\r\n    \"StationNo\": 15,\r\n    \"RunTime\": 1800,\r\n    \"ControllerID\": 4,\r\n    \"ControllerAddress\": 2,\r\n    \"ProgramNo\": 4,\r\n    \"ModeID\": \"AutoProgram\",\r\n    \"EventDate\": \"2022-04-27T22:00:02\",\r\n    \"Description\": \"Irrigation Completed\",\r\n    \"MessageCode\": 5\r\n  },\r\n  {\r\n    \"ID\": 142,\r\n    \"StationNo\": 19,\r\n    \"RunTime\": 1800,\r\n    \"ControllerID\": 4,\r\n    \"ControllerAddress\": 2,\r\n    \"ProgramNo\": 5,\r\n    \"ModeID\": \"AutoProgram\",\r\n    \"EventDate\": \"2022-04-27T22:30:02\",\r\n    \"Description\": \"Irrigation Completed\",\r\n    \"MessageCode\": 5\r\n  }\r\n]",
            "ScaledValue": "[\r\n  {\r\n    \"ID\": 145,\r\n    \"StationNo\": 6,\r\n    \"RunTime\": 1800,\r\n    \"ControllerID\": 4,\r\n    \"ControllerAddress\": 2,\r\n    \"ProgramNo\": 2,\r\n    \"ModeID\": \"AutoProgram\",\r\n    \"EventDate\": \"2022-04-27T23:30:02\",\r\n    \"Description\": \"Irrigation Completed\",\r\n    \"MessageCode\": 5\r\n  },\r\n  {\r\n    \"ID\": 144,\r\n    \"StationNo\": 18,\r\n    \"RunTime\": 1800,\r\n    \"ControllerID\": 4,\r\n    \"ControllerAddress\": 2,\r\n    \"ProgramNo\": 5,\r\n    \"ModeID\": \"AutoProgram\",\r\n    \"EventDate\": \"2022-04-27T22:00:00\",\r\n    \"Description\": \"Irrigation Completed\",\r\n    \"MessageCode\": 5\r\n  },\r\n  {\r\n    \"ID\": 143,\r\n    \"StationNo\": 15,\r\n    \"RunTime\": 1800,\r\n    \"ControllerID\": 4,\r\n    \"ControllerAddress\": 2,\r\n    \"ProgramNo\": 4,\r\n    \"ModeID\": \"AutoProgram\",\r\n    \"EventDate\": \"2022-04-27T22:00:02\",\r\n    \"Description\": \"Irrigation Completed\",\r\n    \"MessageCode\": 5\r\n  },\r\n  {\r\n    \"ID\": 142,\r\n    \"StationNo\": 19,\r\n    \"RunTime\": 1800,\r\n    \"ControllerID\": 4,\r\n    \"ControllerAddress\": 2,\r\n    \"ProgramNo\": 5,\r\n    \"ModeID\": \"AutoProgram\",\r\n    \"EventDate\": \"2022-04-27T22:30:02\",\r\n    \"Description\": \"Irrigation Completed\",\r\n    \"MessageCode\": 5\r\n  }\r\n]",
            "Status": "Normal",
            "ComStatus": null,
            "TimeStamp": "2022-04-28 13:17:39.851"
        }
    ]
}

How do I deserialize this JSON and create a List which contains only values from inside RawValue where each payload inside it will behave as a single element in the list. Also how to remove unwanted \r\n and escaping characters from each element in the list.


Solution

  • You've got JSON containing JSON, basically - so you should expect to have to deserialize once. (If you can change the structure of the JSON to avoid this double-serialization, that would be better, admittedly, but I'll assume that's fixed.)

    For example, you could have:

    public class Root
    {
        public List<Value> Values { get; set; }
    }
    
    public class Value
    {
        // Add other properties if you need them
        public string RawValue { get; set; }
    }
    

    Then:

    string json = ...;
    Root root = JsonConvert.DeserializeObject<Root>(json);
    // This just takes the first value - we don't know whether you actually
    // ever have more than one...
    string rawValue = root.Values[0].RawValue;
    JArray array = JArray.Parse(rawValue);
    

    That assumes you're happy using JArray/JObject for the "embedded" objects. If you want to model those as well, you'd have:

    public class Station
    {
        [JsonProperty("ID")]
        public int Id { get; set; }
        public int StationNo { get; set; }
        // etc
    }
    

    ... then for deserializing:

    string json = ...;
    Root root = JsonConvert.DeserializeObject<Root>(json);
    // This just takes the first value - we don't know whether you actually
    // ever have more than one...
    string rawValue = root.Values[0].RawValue;
    List<Station> stations = JsonConvert.DeserializeObject<List<Station>>(rawValue);
    

    There shouldn't be any "extra" escaping by the time you've deserialized twice.