amnesia amnesia - 1 month ago 12
C# Question

C#: How to change search directory for dependencies of dynamically loaded assemblies within a dynamically loaded assembly?

This is convoluted, but here goes:

For integration with another application (in a separate directory), we are dynamically loading one of its assemblies, then using Activator to instantiate an object from that assembly. The target assembly loads fine, but when creating an instance of the object, it attempts to dynamically load some additional dependencies and fails because it finds a newer version of them in our app dir:

var assm = Assembly.LoadFrom("full.path.to.asm"));
var objType = assm.GetType("MyType", true);
var obj = Activator.CreateInstance(objType);


The
assm
loads fine, and
objType
is obtained. Exception occurs activating
obj
because it's dependent on an older version of an assembly (which it does have in its directory) but it's finding a newer one in our app directory first and complains about it being the wrong signature.

I tried setting Environment.CurrentDirectory first, but it didn't make any difference.

Answer

You need to subscribe to the AppDomain.AssemblyResolve event. In there you can re-direct it to check the other directory for the assembly that is missing.

public static object CreateInstance()
{    
    AppDomain currentDomain = AppDomain.CurrentDomain;
    currentDomain.AssemblyResolve += MyResolveEventHandler;
    var assm = Assembly.LoadFrom("full.path.to.asm"));
    var objType = assm.GetType("MyType", true);
    var obj = Activator.CreateInstance(objType);
}

private static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
{
    if (args.Name == "SomeAssemblyIntheOtherFolder")
    {
        var path = Path.Combine(Path.GetDirectoryName("full.path.to.asm"), "SomeAssemblyIntheOtherFolder.dll");
        return Assembly.LoadFrom(path);
    }
    return null;

}

Update: A 2nd option is add a assembly binding redirect in your app, this makes the other application use the newer version of the dll that you have instead of the version they where compiled with.

Here is a example of it being done with the library Common.Logging.dll, you would put this in your app.config file.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  ...
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
        <dependentAssembly>
            <assemblyIdentity name="Common.Logging" publicKeyToken="af08829b84f0328e" culture="neutral" />
            <bindingRedirect oldVersion="0.0.0.0-3.2.0.0" newVersion="3.2.0.0" />
        </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

What this will do is cause any assemblies that are loaded in your program built to reference any version of the Common.Logging.dll library between 0.0.0.0 and 3.2.0.0 to just use 3.2.0.0 instead of the version they where built with.