views:

227

answers:

2

According to How the Runtime Locates Assemblies step 2 is Checking for Previously Referenced Assemblies.

However, in the code below you can see that this is definitely not happening. In the first line, an assembly is loaded (which should make it a "previously referenced assembly" for all future calls.)

However, a couple lines later when the code calls AppDomain.CurrentDomain.CreateInstance, the AssemblyResolve event is fired, indicating that the runtime is unable to locate the requested assembly.

You can tell the assembly is loaded, because from the AssemblyResolve event I am returning the assembly directly from CurrentDomain.GetAssemblies() !!

So, the obvious question is, why is the runtime not finding the referenced assembly as step 2 of "How the Runtime Locates Assemblies" would imply?

In order to run this example: Create a new console app, then add a new ClassLibrary to that solution and leave it named ClassLibrary1. Paste the below code into the Console Application's class Program:

class Program
{
    static void Main(string[] args)
    {
        Assembly asmbly = Assembly.LoadFile(Path.GetFullPath(@"..\..\..\ClassLibrary1\bin\Debug\ClassLibrary1.dll"));
        Type firstType = asmbly.GetTypes().First();
        AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
        object myInstance = AppDomain.CurrentDomain.CreateInstance(asmbly.FullName, firstType.FullName);
    }

    static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        //WHY AM I HERE?
        return AppDomain.CurrentDomain.GetAssemblies().SingleOrDefault(p => p.FullName == args.Name);
    }
}

then add using references like so:

using System.Reflection;
using System.IO;

Note that I've deliberately left the original paths here such that the runtime will not find the assembly as according to Step 4: Locating the Assembly through Codebases or Probing My scenario is such that I am trying to deliberately use the functionality defined in Step 2. If the runtime can locate the path via Step 4, that will work correctly. It is step 2 that is not working.

Thanks.

+2  A: 

This is a quote from MSDN

Use the LoadFile method to load and examine assemblies that have the same identity, but are located in different paths. LoadFile does not load files into the LoadFrom context, and does not resolve dependencies using the load path, as the LoadFrom method does. LoadFile is useful in this limited scenario because LoadFrom cannot be used to load assemblies that have the same identities but different paths; it will load only the first such assembly.

Here is a great article going into details on how the method used to load an assembly affects the references resolution.

In particular this article states that LoadFile loads assembly into "neither context".

mfeingold
+3  A: 

It's failing to resolve because the assembly was loaded into a different context - the LoadFile context, while AppDomain.CurrentDomain.CreateInstance attempts to resolve the assembly using the Load context.

From "Understand the Context" in Understanding The CLR Binder:

So why does the CLR have loader contexts in the first place? Loader contexts help ensure load-order independence while loading assemblies. In addition, they provide a measure of isolation to assemblies and their dependencies when they are loaded into different contexts.

It looks like you've already solved the problem by subscribing to the AssemblyResolve event, but there are several other approaches you might take, depending on your requirements:

Jeff Sternal
Thanks. That resolved my issue. It seems to me that the "solution" I have in the original post above is actually a decent one in this case. The assembly is loaded, just into the LoadFrom context, not the Load context. So just returning it from AssemblyResolve is a decent solution, and serves to move it into the Load context.
Clever Human
I totally agree - `AssemblyResolve` is a perfectly good solution. (In fact, I was in the process of updating my answer to say exactly that when you left this comment.) :)
Jeff Sternal