Working with Appdomain.Assemblyresolve Event

Working with AppDomain.AssemblyResolve event

You can define a dictionary of the assemblies from your directory, like this:

private readonly IDictionary<string,Assembly> additional =
new Dictionary<string,Assembly>();

Load this dictionary with the assemblies from your known directory, like this:

foreach ( var assemblyName ... corresponding to DLL names in your directory... ) {
var assembly = Assembly.Load(assemblyName);
additional.Add(assembly.FullName, assembly);
}

Provide an implementation for the hook...

private Assembly ResolveAssembly(Object sender, ResolveEventArgs e) {
Assembly res;
additional.TryGetValue(e.Name, out res);
return res;
}

...and hook it up to the event:

AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += ResolveAssembly;
AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly;

This should do the trick.

async AppDomain.AssemblyResolve

Is it possible make my assembly resolve method async?

No. The event signature is synchronous, so your implementation must be synchronous. You'll need to block on asynchronous code.

AssemblyResolve Event Handler vs. CodeBase policies

I see two questions here. Correct me if I'm no providing enough information.

  1. AssermblyResolve event is invoked only if loader doesn't manage to find assembly it is looking for. So, first assembly load locations are probed, and then if assembly is not found, AssermblyResolve event is invoked. If all assemblies are loaded correctly, AssemblyResolve event will not fire at all.

  2. It is possible to load assembly manually to default AppDomain if that is what you mean. When assembly doesn't load correctly, and AssemblyResolve of the AppDomain fires, you have a chance to resolve it manually.

First you attach to the event to get informed that loading an assembly has failed

AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;

And then try to load replacement assembly from a different place, depending on your criteria:

static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (args.Name == "ClassLibrary1, Version=2.0.0.0, Culture=neutral, PublicKeyToken=e261024fcc198a53")
return Assembly.LoadFile("d:\\differentPath\\ClassLibrary1.dll");
else
return null;
}

Binding redirects as far as I know are useful for redirecting to a different version of assembly, but not redirecting loader to specific path where to look for assemblies.

Can a call to Assembly.Load(byte[]) raise the AppDomain.AssemblyResolve event?

To my knowledge Assembly.Load or loading assembly by other means does not execute any constructors that can be generated by the C# compiler (including static constructors). As result you're not going to get reentrancy to AssemblyResolve on commonly found assemblies.

As you've mentioned in the question, module initializers are not executed during the Load call. Covered in list of guarantees in CLI spec - excerpt can be found in Module Initializers by Junfeng Zhang.

B. The module’s initializer method is executed at, or sometime before, first access to any types, methods, or data defined in the module

There are related SO questions usually discussing "run code before any type constructors" like Initialize library on Assembly load. Note that .Net: Running code when assembly is loaded has an answer by Marc Gravell that states it may not be possible due to security constraints.

AssemblyResolve not fired

The behavior you see is caused by method inlining that might be performed by .NET runtime.

To make your scenario work, please ensure that affected method is not inlined. Like so:

class Bar {
static Bar() {
Resolver.Setup();
}

public voidFoo() {
_DoTheJob();
}

[MethodImpl(MethodImplOptions.NoInlining)]
void _DoTheJob() {
var foo = new Foo();
//...
}
}

Once method is not inlined, it is guaranteed that your resolver will be installed first, and the assembly containing ClassFromAssembly will be loaded after the resolver is installed.

P.S. Also ensure that assembly of interest is not loaded before you install the assembly resolver. Otherwise, the missed assembly references won't be resolved and those failures will be cached in current AppDomain forever, e.g. you will never get AssemblyResolve event for them again.

Can I use AppDomain.AssemblyResolve Event to redirect a failed Assembly Load?

You cannot load 32-bit DLLs into 64-bit processes. "Any CPU" assemblies work because the JIT handles the IL compilation before execution, creating a native image of the appropriate type; CPU-specific assemblies don't support JITing to different types.

This is a Windows limitation, not a CLR limitation.

AppDomain.CurrentDomain.AssemblyResolve does not fire while loading plug-in for main software. Why?

As described in EDIT #4 the assembly event was not registered soon enough.

I solved the problem by removing PLUGINStarter and moving the assembly resolving code to the constructor of Loader.cs. Now everything resolves nicely despite wrong assembly versions.



Related Topics



Leave a reply



Submit