Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serialize & Deserialize a dictionary that contain a class key

Im trying to serialize my dictionary that looks like that:

private Dictionary<MetaDataKey, User> _dictionary;

where MetaDataKey and Users classes looks like that:

internal class User
{
    public string UserName { get; set; }
    public string UserPassword { get; set; }
    public List<Account> Accounts { get; set; }
}
internal class Account
{
    public string Subject { get; set; }
    public string AccName { get; set; }
    public string AccPass { get; set; }
    public List<string> Notes { get; set; }
}
internal class MetaDataKey
{
    public string Name { get; set; }
    public string Password { get; set; }
}

I am trying to save\load the dictionary to\from a json file like this:

private void DictionaryInit()
    {
        //gets the dictionary file if exists, create an empty one if not.
        string path = Directory.GetCurrentDirectory() + "\\dic.json";
        if (!File.Exists(path))
        {
            _dictionary = new Dictionary<MetaDataKey, User>();
            return;
        }
        using (StreamReader r = new StreamReader(path))
        {
            string json = r.ReadToEnd();
            _dictionary = JsonConvert.DeserializeObject<Dictionary<MetaDataKey, User>>(json);
        }
    }

    public void DictionarySave()
    {
        //save the dictionary into dic.json file
        string path = Directory.GetCurrentDirectory() + "\\dic.json";
        string json = JsonConvert.SerializeObject(_dictionary);
        File.WriteAllText(path, json);
    }

when I am loading a new record to the dictionary and trying to save it I get:

{"WpfApplication2.MetaDataKey":{"UserName":"Enter Name","UserPassword":"Enter Password","Accounts":null}}

instead of:

{"WpfApplication2.MetaDataKey":{"Name":"Enter Name","Password":"Enter Password"},"WpfApplication2.User":{"UserName":"Enter Name","UserPassword":"Enter Password","Accounts":null}}

as you can tell, I am getting the fields of Users in MetaDataKey class. even after I fix it manualy I am still getting exception:

An exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll but was not handled in user code

when I am trying to load a non-empty file. In conclusion, 2 problems: 1. bad json saving. 2. bad json loading

like image 738
Etian Chamay Avatar asked Nov 25 '25 22:11

Etian Chamay


1 Answers

From the documentation of Json.Net:

When serializing a dictionary, the keys of the dictionary are converted to strings and used as the JSON object property names. The string written for a key can be customized by either overriding ToString() for the key type or by implementing a TypeConverter. A TypeConverter will also support converting a custom string back again when deserializing a dictionary.

You have two options:

  1. like the documentation suggests: create a TypeConverter for your MetaDataKey and link it with attribute ([TypeConverter(typeof(MetaDataKeyConverter))]) - This is not trivial as you will have to convert the MetaDataKey to json string yourself, and also deserialize from string.
  2. Create a JsonConverter for dictionary and use it in your JsonConvert.SerializeObject and JsonConvert.DeserializeObject methods.
  3. The simplest thing you can do is to convert the dictinary to a List<KeyValuePair<MetaData,User>> this is easy as _dictionary.ToList()
    So for serializing:

    string json = JsonConvert.SerializeObject(_dictionary.ToList());
    

    And for deserialize:

    _dictionary = 
                JsonConvert.DeserializeObject<List<KeyValuePair<MetaDataKey, User>>>(json)
               .ToDictionary(kv => kv.Key, kv => kv.Value);
    

For most cases I would choose option 3

like image 111
Ofir Winegarten Avatar answered Nov 27 '25 13:11

Ofir Winegarten



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!