4

I'm dynamically loading an assembly using Assembly.LoadFrom(), then instantiating some of its types using .CreateInstance(). Next, I put these objects into an array and serialize it to a file using json.net (configured with TypeNameHandling.Auto). In the file I can see that it is storing the correct type names, e.g.:-

"Features": [{
    "$type": "FeaturesAssembly.SomeFeature, FeaturesAssembly",
    // Other serialized properties
}]

The problem is that I can't deserialize the file. Json.net throws a JsonSerializationException, message "Could not load assembly 'FeatureAssembly'", despite the necessary assembly having been dynamically loaded first. What am I missing?

Andrew Stephens
  • 9,413
  • 6
  • 76
  • 152

2 Answers2

6

This looks to me like it might be a bug/limitation in Json.NET.

Digging into the source for DefaultSerializationBinder.GetTypeFromTypeNameKey() (viewable e.g. here), the binder first tries to load the desired assembly by partial name from the app directory and GAC. If that fails, it compares the desired assembly name against the fully-qualified names of all assemblies loaded in the current app domain.

This last step will never find a match when the JSON document contains only the simple assembly name (the default), even if the required assembly has already been loaded in the current app domain.

One possible fix would be for the binder to compare the desired assembly name against each assembly's fully-qualified and simple names.

Matt Craig
  • 158
  • 6
  • This problem is still present in Newtonsoft Json.NET version 9.0.1 – marsop Jan 26 '17 at 08:20
  • What appears to be the case is that there is a compilation switch in GetTypeFromTypeNameKey() that disables the possibility to search for loaded assemblies in the AppDomain (as can be seen here https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Serialization/DefaultSerializationBinder.cs) – marsop Jan 26 '17 at 09:27
  • This does appear to work now with assembly's loaded in Json.NET 10.0.1 – Stu Wilson Mar 23 '17 at 15:41
  • I've updated from version 9.0.1 to 11.0.2 and the issue is now solved. – Ahmad Ibrahim Jul 31 '18 at 10:23
3

Try changing your serializer settings to include the following:

jsonSerializerSettings.TypeNameAssemblyFormat =
    System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Full;
Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
  • 1
    That did it! However I notice it includes the assembly version number in the type name, which is no good for me as I'll need to maintain backwards compatibility and deserialize types from older builds (although I realise this sort of versioning comes with its own pitfalls). In the meantime I've been looking into json.net custom converters, and hopefully I can come up with a solution using those. I've accepted yours as the answer, as it does answer my original question! – Andrew Stephens Jul 18 '14 at 08:00
  • 1
    Glad to help. I think the fact that it has the version number and public key in there is what makes it able to reliably find and create the type. If that doesn't work for your situation, then yeah, you'll have to use a converter and introduce your own custom mechanism for indicating the type to create. Here is a [question](http://stackoverflow.com/q/19307752/10263) and [answer](http://stackoverflow.com/a/19308474/10263) that might help get you started--it shows how to create a converter that uses other information in the JSON to determine what type of object to create. – Brian Rogers Jul 18 '14 at 13:35
  • Hey @BrianRogers, we're having the same issue, but the fix you mentioned here isn't working (it says that it's deprecated), assuming you're meaning the `SerializerSettings` passed to the `DeserializeObject()` call? We also tried `TypeNameHandling = TypeNameHandling.Auto` and `TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Full` but to no avail. We get `Could not load file or assembly`. If we fully qualify the path to the assembly in the $type element, we get a different error: `The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047)` – Jesse Pepper Feb 20 '19 at 11:19
  • @JessePepper If you are still having trouble with this, you should create a new question for it, including all the details of things you've tried and example code if possible. You can include [a link back to this question](https://stackoverflow.com/q/24807110/10263) to help provide context. That way more people will see it and will be able to respond properly with answers. Comments do not work well for that. – Brian Rogers Mar 30 '19 at 21:29