Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get a type from an assembly that is loaded from within another folder?

I use the following code:

Assembly.LoadFile("the assembly in another folder");
var type = Type.GetType("the full name of the type");

Even though the assembly was already loaded before this line of code, it always returns null in type.

PS: I did pass in the assembly qualified name, including namespace, type name, assembly name, version and public token.

like image 347
Cui Pengfei 崔鹏飞 Avatar asked Nov 04 '11 16:11

Cui Pengfei 崔鹏飞


2 Answers

Type.GetType only searches the types in the calling assembly and the types in mscorlib.dll unless you pass the assembly qualified name of the type. See here.

EDIT

It appears that Type.GetType is only able to retrieve Type instances from assemblies in the Load context. Assemblies loaded using LoadFile are in no context and those loaded using LoadFrom are in the Load From context; neither of these contexts allow you to use Type.GetType so the resolution will fail. This article shows that Type information can be retrieved for an Assembly when the directory it is in is added as a probing privatePath since it will then end up in the Load context but will fail in other contexts.

like image 163
Steve Rowbotham Avatar answered Oct 07 '22 18:10

Steve Rowbotham


The "proper" (MS recommended) way to do this, when you must use Type.GetType(string) on types in assemblies that are not in the load context but in the load-from or no-context context, is to bind to the Appdomain.AssemblyResolve event. The following code is relatively efficient:

// this resolver works as long as the assembly is already loaded
// with LoadFile/LoadFrom or Load(string) / Load(byte[])
private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
{
    var asm = (from a in AppDomain.CurrentDomain.GetAssemblies()
              where a.GetName().FullName == args.Name
              select a).FirstOrDefault();

    if(asm == null)
         throw FileNotFoundException(args.Name);     // this becomes inner exc

    return asm;
}

// place this somewhere in the beginning of your app:
AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;

It appears slightly more efficient to create a combination of the AssemblyLoad/Resolve events to keep a dictionary of the loaded assemblies (use the assembly-name as key).

On Assembly.LoadFile
There are some serious drawback on using this method. According to MSDN:

LoadFile does not load files into the LoadFrom context, and does not resolve dependencies using the load path, as the LoadFrom method does.

So, if possible, do not use LoadFile. The resulting assembly is loaded in the no-context context, which has even more drawbacks than the load-from context. Instead, use Assembly.LoadFrom and dependencies will be automatically loaded from the load path.

like image 23
Abel Avatar answered Oct 07 '22 19:10

Abel