Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Method not found" exception. Why AppDomain.CurrentDomain.AssemblyResolve doesn't work?

Tags:

c#

.net

  1. There is an application (executor.exe) that invokes methods from class library (lib.dll) using reflection.
  2. executor.exe has assembly Newtonsoft.Json version 8.0 as embedded resource.
  3. lib.dll has reference to Newtonsoft.Json version 9.0.
  4. lib.dll has reference to system.net.http.formatting version 4.0.0.21112, which in turn refers to Newtonsoft.Json 4.5.
  5. I don't have the opportunity to modify executor.exe.config (except for testing).

What do I want to get:

new JsonMediaTypeFormatter().SerializerSettings;

Invoked from lib.dll. But it fails with:

Method not found: 'Newtonsoft.Json.JsonSerializerSettings System.Net.Http.Formatting.JsonMediaTypeFormatter.get_SerializerSettings()'

What I was trying to do:

  1. Handling AppDomain.CurrentDomain.AssemblyResolve (subscribed correctly, using ModuleInitializer). But it doesn't rise. After crash have 2 Newtonsoft.Json (with different versions) loaded to AppDomain.
  2. Binding in app config:

     <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed"
     culture="neutral" />
     <bindingRedirect oldVersion="4.0.0.0-5.0.0.0" newVersion="9.0.0.0" />
    

Yes, it works. But I can't use this solution. After passing have 2 Newtonsoft.Json (with different versions) loaded to AppDomain.

  1. I don't understand why this works (oldVersion="8.0.0.0-9.0.0.0") but:

    <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
    <bindingRedirect oldVersion="8.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
    

exception "Method not found" doesn't throw. After passing have 1 Newtonsoft.Json (9.0) loaded to AppDomain. But not suitable for me.

Why AppDomain.CurrentDomain.AssemblyResolve doesn't work? I guess the problem is in 2 loaded assemblies but I can not change this behavior.

like image 469
Hopeless Avatar asked Nov 16 '17 01:11

Hopeless


2 Answers

Why AppDomain.CurrentDomain.AssemblyResolve doesn't work?

Event AppDomain.CurrentDomain.AssemblyResolve is fired if assembly resolution fails. It's not your case since you see Newtonsoft.Json assembly already loaded in the application domain.

You catch MissingMethodException because System.Net.Http.Formatting.JsonMediaTypeFormatter.get_SerializerSettings() returns JsonSerializerSettings declared in Newtonsoft.Json version 4.5. Unfortunatelly, for soulless CLR JsonSerializerSettings from Newtonsoft.Json 4.5 is not the same at all as JsonSerializerSettings from Newtonsoft.Json 9.0.

To fix this problem, mechanism for redirection of assembly versions was introduced (bindingRedirect that you refer to).

exception "Method not found" doesn't throw. After passing have 1 Newtonsoft.Json (9.0) loaded to AppDomain. But not suitable for me.

Actually that's the solution you should stick to. Your best option is to have only one Newtonsoft.Json assembly loaded into application domain and have version redirection configured.

Why would you reinvent the wheels and try to find solution other than platform offers? If for some strange reason you're prohibited to modify application config, you could add assembly redirection on machine level See this article for details. But assembly version redirection is the way how eternal DLL hell problem is fixed in .Net. Using any other workarounds (even if you manage to find them) will make you no good.

like image 119
CodeFuller Avatar answered Nov 11 '22 06:11

CodeFuller


If you cannot apply binding redirects you can also load correct assembly on application startup use Assembly.LoadFrom method. In main method find Newtonsoft.Json dlls and load one with the version you need. That should avoid loading of assembly with incorrect version. Let me know if you want me to provide a code snippet for you.

like image 21
Andrii Litvinov Avatar answered Nov 11 '22 07:11

Andrii Litvinov