LupusRex
LupusRex

Reputation: 53

Deserialize Json an access the result

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

Upvotes: 5

Views: 297

Answers (4)

Pavel Anikhouski
Pavel Anikhouski

Reputation: 23258

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)

Upvotes: 6

RoadRunner
RoadRunner

Reputation: 26325

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.

Upvotes: 2

Atharva
Atharva

Reputation: 839

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': '[email protected]',
  '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

Upvotes: 2

Serkan Arslan
Serkan Arslan

Reputation: 13393

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"
      }
   }
}

Upvotes: 0

Related Questions