1

I'm working on a small (.Net 5 wpf) app, which loads and saves its state from/into json files (using Newtonsoft library). I save it with $type and $id fields.

Now I have added a plugin system, where I load assemblies from a folder and create objects from them into my app state (say, my model/viewmodel). When I'm saving my model, everything runs fine. I checked the $type, and it's the real name.

My issue is: how to load it back (without writing custom parsing code) ? My plugin types are stored in a List in my plugin service, and newtonsoft has no knowledge of them. So, I have 2 questions:

  • how do I tell newtonsoft lib to take my types into account ?
  • and/or how do I tell the environment running my app (framework ? app domain ?) to meet my types, and consider them as known for the rest of the time my app is launched ?

I have no useful code to show cause everything happens in a DeserializeObject() method.

Ok let's illustrate as asked in the comments.

    // Loading of my types. I can call it for deserialization if needed
    var asm = Assembly.LoadFile("plugin.dll");
    var typeX = asm.GetTypes().First();
    var instance = Activator.CreateInstance(typeX) as BaseClass;
    
    //Items is a List<BaseClass>
    myModel.Items.Add(instance);
    
    JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
    string serialized = JsonConvert.SerializeObject(myModel, Formatting.Indented, settings);
    File.WriteAllText(path, serialized);
    
    // HERE: JSonConvert does not know my type typeX !
    var readObject = JsonConvert.DeserializeObject<TypeOfMyModel>(content, settings);

I'd like to be able to say to JsonConvert, "hey, you might need these types too when deserializing my model, depending on what you encounter". Cause JsonConvert knows how to deserialize a class embedded known at compile type, but not one from an assembly I dynamically loaded.

Thank you for any help.

[edit] @dbc gave me the solution in the comments: using a custom SerializationBinder gives the ability to solve the type. Thanks !

Poc
  • 109
  • 10
  • _"My plugin types are stored in a List in my plugin service, and newtonsoft has no knowledge of them"_ - please illustrate. – ProgrammingLlama Dec 03 '21 at 01:05
  • _"how do I tell newtonsoft lib to take my types into account ?"_ - you don't. It will serialize or deserialize to/from any type you pass it to. – ProgrammingLlama Dec 03 '21 at 01:05
  • @Llama I tried before posting, it doesn't. I tried to describe the issue with some code. – Poc Dec 03 '21 at 02:07
  • What is `etl`? and what is `Etl`? How do you conclude from that last line that it doesn't know `typeX`? You're using the generic overload and passing ``, you're not passing `typeX`... – ProgrammingLlama Dec 03 '21 at 02:14
  • @Llama, sorry I missed this change. I updated the post. I serialize my model with the generic version, yes. Because my model is of type TypeOfMyModel. But it contains a typeX after I instanciated it. – Poc Dec 03 '21 at 02:18
  • 1
    You need to post an example that reproduces the problem. There is no way for anyone to understand what you're trying to do because we can't run it ourselves. – David L Dec 03 '21 at 02:54
  • `var readObject = ` ... then what? Can the caller provide the type via generics? – Jeremy Lakeman Dec 03 '21 at 02:56
  • @JeremyLakeman then nothing, it fails, because if I added a TypeX, JsonConvert has only a json file to deserialize, which says "hey, I have a typeX in my list". And it doesn't know what to do with it, because how could it ? That's my question actually :) – Poc Dec 03 '21 at 04:30
  • No, I mean then what are you going to do with that object? Will the next step implicitly provide type information that you can use? – Jeremy Lakeman Dec 03 '21 at 06:56
  • @JeremyLakeman the next step builds a viewmodel out of the deserialized model. So no, it has to be completely loaded. If I had a typeX to load, I'd say that to JSonConvert, and voila. Nothing more to say, _and JSonConvert would know what is a typeX_. But I have a model that has a list of BaseClass. Amongst them, 0,1,... n typeX. That it has no knowledge of given that I asked it to deserialize a _TypeOfMyModel_ – Poc Dec 03 '21 at 08:45
  • 1
    If your problem is that you need to load some specific assembly during deserialization, and newtonsoft doesn't know from where to load it, you could do that in a [pcustom serialization binder](https://www.newtonsoft.com/json/help/html/SerializeSerializationBinder.htm). Or, you could use an `AppDomain.CurrentDomain.AssemblyResolve` callback. See e.g. [Binary serialization with dynamically loaded .Net assembly](https://stackoverflow.com/q/18881659/3744182). That question is for `BinaryFormatter` but Json.NET's `ISerializationBinder` is very similar to the .Net `SerializationBinder`. – dbc Dec 03 '21 at 14:34
  • And see [Serializing in Azure Function](https://stackoverflow.com/q/45444942/3744182) or [Why do I get errors when trying to resolve a derived type during deserialization? (Newtonsoft.Json)](https://stackoverflow.com/q/59281162/3744182) for Json.NET examples. Note that early version of Json.NET used `SerializationBinder` while later versions use [`ISerializationBinder`](https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Serialization_ISerializationBinder.htm) so older answers may need tweaking. Do those answer your question? If not, can you share a [mcve] with more details? – dbc Dec 03 '21 at 14:40
  • @dbc Thank you ! The SerializationBinder works fine, this is what I was looking for, now I can deserialize my model correctly. I can't mark your comment as the answer as it is a comment but it helped a lot ! – Poc Dec 04 '21 at 15:40
  • Glad to help. Let's mark it as a dup of [Serializing in Azure Function](https://stackoverflow.com/q/45444942/3744182) then. – dbc Dec 04 '21 at 16:10

0 Answers0