0

I want to Serialize a Dictionary which contains different kinds of objects (dynamic) and save it to a file. When loading the file, the software needs to DeSerialize the data to a Dictionary again and set the objects references. When I try to set an object, it gives me the error:

Cannot implicitly convert type 'Newtonsoft.Json.Linq.JObject' to 'PartyCreator.Member'.

It seems like the DeSerialized Dictionary is working, i can access the member1 properties using loadedObjects["member1"].Name for example but can't reference the object to an already existing object member1 created from my own Member class.

// Serializing the Dictionary           
Dictionary<string, dynamic> savedObjects = new Dictionary<string, dynamic>();

savedObjects.Add("member1", member1);
savedObjects.Add("member2", member2);
savedObjects.Add("member3", member3);
savedObjects.Add("member4", member4);   

var settings = new JsonSerializerSettings() { ContractResolver = new MyContractResolver() };
var saveData = JsonConvert.SerializeObject(savedObjects, settings);

// DeSerializing the Dictionary
Dictionary<string, dynamic> loadedObjects = new Dictionary<string, dynamic>();
loadedObjects = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(saveData);

member1 = loadedObjects["member1"]; // Giving an error: Cannot implicitly convert type 'Newtonsoft.Json.Linq.JObject' to 'PartyCreator.Member'

// These are the settings i'm using with Json Serializer
public class MyContractResolver : Newtonsoft.Json.Serialization.DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        var props = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                    .Select(p => base.CreateProperty(p, memberSerialization))
                    .Union(type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                    .Select(f => base.CreateProperty(f, memberSerialization)))
                    .Where(p => !p.PropertyName.Contains("k__BackingField"))
                    .ToList();
            props.ForEach(p => { p.Writable = true; p.Readable = true; });
            return props;
    }
}
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • You can access the value in dictionary by key like `loadedObjects["member1"].Value();` – Pavel Anikhouski Jan 01 '20 at 17:27
  • check this excerpt from Adam Freemen out https://github.com/Apress/pro-asp.net-core-mvc-2/blob/master/10%20-%20SportsStore%20-%20Cart/SportsStore/SportsStore/Infrastructure/SessionExtensions.cs – Bryan Dellinger Jan 01 '20 at 17:29
  • 1
    JSON does not store c# type information, so when you serialize to JSON the actual type of your `dynamic` objects is lost. To store type information, set `TypeNameHandling.Auto` as shown in [this answer](https://stackoverflow.com/a/40403520/3744182). [how to deserialize JSON into IEnumerable with Newtonsoft JSON.NET](https://stackoverflow.com/q/6348215/3744182) also discusses the problem as does [How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects?](https://stackoverflow.com/q/8030538/3744182). – dbc Jan 01 '20 at 17:32
  • 1
    But using `TypeNameHandling` introduces security vulnerabilities into your app, see [TypeNameHandling caution in Newtonsoft Json](https://stackoverflow.com/q/39565954/3744182) and [External json vulnerable because of Json.Net TypeNameHandling auto?](https://stackoverflow.com/q/49038055/3744182). – dbc Jan 01 '20 at 17:34

0 Answers0