Search code examples
c#.netreflection.net-assemblyprobing

Assembly path when created by Reflection (C#)


I have a strange situation where the wrong assembly is used when created by reflection.

This is my setup (simplified):

Project1: Class Library

Project2: client app

  • Project2 creates Project1.dll by reflection from a specific path (C:\Project1)
  • Project2 additionally has a reference to Project1.dll for different functionality. This reference copies Project1.dll in C:\Project2\bin\Debug.

Relevant reflection code is:
Assembly assembly = Assembly.LoadFrom(path);

Problem: When I call Project1 by reflection, even though I specify the C:\Project1 path, it actually uses the bin\Debug copy (which is not necessarily the right version).

Question: How do I ensure the path I supply is used instead of whatever version it finds first ?

My ideal solution would be to split Project1 in two, one for reflection and one for reference, but that is not an option in my case (it is but it has additional complications).

Thank you,
Simon


Solution

  • Thanks for updating your post. This single line shows why you are encountering this behavior.

    The method LoadFrom works as defined:

    The load-from context contains assemblies for which the user provided a path not included in the directories searched by probing. LoadFrom, CreateInstanceFrom, and ExecuteAssembly are examples of methods that load by path.

    Probing is the process of looking in the GAC, the host assembly store, the folder of the executing assembly, or the private folder of the executing assembly to find the assembly.

    As you already referenced the assembly, it just returns the already-loaded assembly that match with the name you supplied in parameter.

    The method you are looking for is LoadFile. MSDN states the following:

    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.


    Additional resources

    LoadFile vs. LoadFrom written by Suzanne Cook on her blog .NET CLR Notes.

    Be careful - these aren't the same thing.

    LoadFrom() goes through Fusion and can be redirected to another assembly at a different path but with that same identity if one is already loaded in the LoadFrom context. LoadFile() doesn't bind through Fusion at all - the loader just goes ahead and loads exactly* what the caller requested. It doesn't use either the Load or the LoadFrom context.

    So, LoadFrom() usually gives you what you asked for, but not necessarily. LoadFile() is for those who really, really want exactly what is requested. (*However, starting in v2, policy will be applied to both LoadFrom() and LoadFile(), so LoadFile() won't necessarily be exactly what was requested. Also, starting in v2, if an assembly with its identity is in the GAC, the GAC copy will be used instead. Use ReflectionOnlyLoadFrom() to load exactly what you want - but, note that assemblies loaded that way can't be executed.)

    LoadFile() has a catch. Since it doesn't use a binding context, its dependencies aren't automatically found in its directory. If they aren't available in the Load context, you would have to subscribe to the AssemblyResolve event in order to bind to them.