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.
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.It is possible to load assembly manually to default
AppDomain
if that is what you mean. When assembly doesn't load correctly, andAssemblyResolve
of theAppDomain
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
How to Write to a Onenote 2013 Page Using C# and the Onenote Interop
How to Programmatically Select an Item in a Wpf Treeview
An Elegant Way to Consume (All Bytes of A) Binaryreader
Different Forms of the Wcf Service Contract Interface
Async Await VS Getawaiter().Getresult() and Callback
Http Error 500.19 When Publish .Net Core Project into Iis with 0X80070005
How to Create an Instance from a String in C#
Regex Word Boundary Expressions
Using Linq Except Not Working as I Thought
What's Difference Between Environment.Exit() and Application.Shutdown()
Performance Cost of 'Try' in C#
Simple Way to Display Row Numbers on Wpf Datagrid
How to Figure Out Which Key of Modelstate Has Error
Is There a .Net Way to Enumerate All Available Network Printers
C# - Making All Derived Classes Call the Base Class Constructor