Deserialize Json an access the result

Viewed 190

I have this Json:

{
   "UpdatePack":"updatePacks\/1585654836.pack",
   "Updates":[
      {
         "Name":"MsgBoxEx",
         "version":"1.5.14.88",
         "ChangeLog":"BugFix: Form didn't resize correct.",
         "Hash":"5FB23ED83693A6D3147A0485CD13288315F77D3D37AAC0697E70B8F8C9AA0BB8"

},
      {
         "Name":"Utilities",
         "version":"2.5.1.58",
         "ChangeLog":"StringManagement updated.",
         "Hash":"05E6B3F521225C604662916F50A701E9783E13776DE4FCA27BE4B69705491AC5"

}

]
}

I have created 2 classes to be used to Deserialize it.

class UpdatesList
{
    public string Name { get; set; }
    public string Version { get; set; }
    public string ChangeLog { get; set; }
    public string Hash { get; set; }
}
class JsonObjectHolder
{
    public string UpdatePack { get; set; }
    //public Dictionary<int, MyData> { get; set; }
    public Dictionary<int, UpdatesList> Updates { get; set; }
}

But when I try to access the dictionary, I keep getting Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object. at " Console.WriteLine(jsonTest.Dict.Count);"

Am I Deserializing it wrong, or do I need to do some thing else to access the result of the dictionary?

I'm new to both C# and Json.

I hope that some one could point me in the right direction on how to handle this.

I'm using Visual Studio 2019 latest update, and .net 4.8. Regards /LR

4 Answers

You code doesn't work because 0 and 1 tokens just a properties, not the array items (you don't have square brackets [] around them). You can parse these values to desired structure manually using JObject

var json = JObject.Parse(your_json_string);
var dict = new Dictionary<int, UpdatesList>();
foreach (var item in json.Properties())
{
    if (item.Value.Type == JTokenType.Object)
    {
        var index = int.Parse(item.Name);
        var updateList = item.Value.ToObject<UpdatesList>();
        dict.Add(index, updateList);
    }
}

var holder = new JsonObjectHolder
{
    UpdatePack = json["Updates"]?.Value<string>(),
    Dict = dict
};

Update: According to OP changes made to JSON it might be deserialized even more simply

var list = json["Updates"]?.ToObject<List<UpdatesList>>();

var holder = new JsonObjectHolder
{
    UpdatePack = json["UpdatePack"]?.Value<string>(),
    Dict = list.Select((updatesList, index) => new { updatesList, index })
                    .ToDictionary(x => x.index, x => x.updatesList)
};

The main point here is that Updates is an array of items, not the key-value collection. It can be transformed into Dictionary<int, UpdatesList> using ToDictionary method from System.Linq (or just use List<UpdatesList> as is)

The exception you're getting essentially means the value is being accessed before the object is initialized.

A better, simpler and cleaner way to doing it is using NewtonSoft. (you can easily get it as a Nuget package)

example:

public class Account
{
    public string Email { get; set; }
    public bool Active { get; set; }
    public DateTime CreatedDate { get; set; }
    public IList<string> Roles { get; set; }
}

and then usage:

string json = @"{
  'Email': 'james@example.com',
  'Active': true,
  'CreatedDate': '2013-01-20T00:00:00Z',
  'Roles': [
    'User',
    'Admin'
  ]
}";

Account account = JsonConvert.DeserializeObject<Account>(json);

Console.WriteLine(account.Email);

Source: https://www.newtonsoft.com/json/help/html/DeserializeObject.htm

I don't see why you need Dictionary<int, UpdatesList> Updates, when you can easily just use List<Update> Updates, since your updates are in a JSON array.

I would model your classes like this:

public class Update
{
    public string Name { get; set; }
    public string Version { get; set; }
    public string ChangeLog { get; set; }
    public string Hash { get; set; }
}

public class RootObject
{
    public string UpdatePack { get; set; }
    public List<Update> Updates { get; set; }
}

You can then deserialize with:

 JsonConvert.DeserializeObject<RootObject>(json);

Try it out on dotnetfiddle.net

Note: To convert JSON to C# classes, you can go to Edit -> Paste Special -> Paste JSON as Classes inside Visual Studio. Make sure you have copied the JSON to your clipboard before using it. You will get classes similar to above.

your data and the class is not compatible. if you change the string like this it would work.

change "Updates" to "UpdatePack" and add "Dict" around the dictionary items.

{
   "UpdatePack":"updates\/4D1D7964D5B88E5867324F575B77D2FA.zip",
   "Dict":{
      "0":{
         "Name":"MsgBoxEx",
         "Version":"1.0.123.58",
         "ChangeLog":"Bugfix:Form didn't resize correct",
         "hash":"AA94556C0D2C8C73DD217974D252AF3311A5BF52819B06D179D17672F21049A6"
      },
      "1":{
         "Name":"Utilities",
         "Version":"1.5.321.87",
         "ChangeLog":"StringManagement updated",
         "hash":"2F561B02A49376E3679ACD5975E3790ABDFF09ECBADFA1E1858C7BA26E3FFCEF"
      }
   }
}
Related