C# Assembly.Load vs Assembly.ReflectionOnlyLoad

Solution 1:

As per Jon's reply, it would be helpful to know what's in LoaderExceptions. In lieu of this information, I think I can hazard a guess. From MSDN:

If the assembly has dependencies, the ReflectionOnlyLoad method does not load them. If you need to examine them, you must load them yourself.

You need to attach a handler to AppDomain.ReflectionOnlyAssemblyResolve to help the CLR load any dependencies of the assembly you're loading. Have you done this?

Solution 2:

The ReflectionOnly methods are the only way you can load a specific Assembly on disk to examine without going via the usual Load/LoadFrom rules. For example, you can load a disk-based assembly with the same identity as one in the GAC. If you tried this with LoadFrom or LoadFile, the GAC assembly is ALWAYS loaded.

Additionally, you may not call GetCustomAttributes(...) on the return Assembly instance since this will attempt to instantiate the Attributes on the assembly, which are ReflectionOnly. You must use CustomAttributeData class's static methods for this.

No types in an assembly loaded via ReflectionOnly may be instantiated.

Solution 3:

I believe your general understanding of the differences between Load and ReflectionOnlyLoad is correct. The problem here (I think) is that even to simply load a type, the CLR needs to read the metadata from the assembly the type itself is defined in as well load the metadata from every assembly the type's ancestors are defined in. So, you need to call Assembly.ReflectionOnlyLoad on all assemblies that define types that are ancestors of the types you're loading.

To give an example, suppose you have the following class defined in assembly A.dll.

public class MyBase
{
   public void Foo() { }
}

and the following class defined in assembly B.dll.

public class MySubclass : MyBase
{
}

When you call Assembly.GetTypes on assembly B.dll, the CLR will try to load the type MySubclass and all of its members. Because the method Foo is defined in MyBase in assembly A.dll (and exists nowhere in the metadata of B.dll), the CLR will throw the type load exceptions if assembly A.dll has not been loaded.

Solution 4:

No method can be executed from assembly, loaded with ReflectionOnlyLoad(), you will get InvalidOperationException. So this is safe way to determine assembly content using reflection.

Solution 5:

Another big difference between the two is Assembly.Load adds the assembly into the AppDomain where as Assembly.ReflectionOnlyLoad will not add the assembly in to the AppDomain

code to show in detail.

public void AssemblyLoadTest(string assemblyToLoad)
{
    var initialAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //4

    Assembly.ReflectionOnlyLoad(assemblyToLoad);
    var reflectionOnlyAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //4

    //Shows that assembly is NOT loaded in to AppDomain with Assembly.ReflectionOnlyLoad
    Assert.AreEqual(initialAppDomainAssemblyCount, reflectionOnlyAppDomainAssemblyCount); // 4 == 4

    Assembly.Load(assemblyToLoad);
    var loadAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //5

    //Shows that assembly is loaded in to AppDomain with Assembly.Load
    Assert.AreNotEqual(initialAppDomainAssemblyCount, loadAppDomainAssemblyCount); // 4 != 5
}