I have a side project on reflection where I try to reproduce Lutz Roeder’s Reflector in such a way as to allow me to inspect several issues within my projects. This has led me to research into all kinds of issues from MSIL to C# code model and Reflection, the latest one becoming one of my favorite topics from .NET technologies.
My lattest hurdle was to overcome the devious “FileNotFoundException” when trying to resolve a type which is not in the main loaded assembly for reflection.
What happens? Let’s suppose you load an assembly which you want to inspect using reflection. You would use something like:
Assembly assembly = Assembly.LoadFile(path);
Type[] types = assembly.GetTypes();
MethodInfo[] methods = types[0].GetMethods();
ParameterInfo[] parameters = methods[0].GetParameters();
Then you start the usual work of gettting the types and then get the methods of one of the types and then of course try to see something like the parameters of one of the methods. Ain’t reflection great?
NO. Not if you don’t know how to use it. Because when you hit the line where you want to load the parameters of a method, the application will crash with a “FileNotFoundException” when the dll inspected is not in the same directory as the executable that is loading that assembly. Why the hell is that happening. Well I scoured the net for an answer and all where giving partial responses but none were actually giving me a sollution.
Let’s consider the following.
namespace A
{
public class C1
{
}
}
namespace B
{
public class C2
{
public void MyMethod(A.C1 param1)
{
}
}
}
And let’s consider that the namespaces A and B are declared in separate projects and thus result in two different dlls and the project that defines namespace B references the project that defines namespace A.
Now you want to load the “B.dll” to inspect the parameters from method “MyMethod” and you use the code I described above. Here the runtime will fail because he does not have a definition of the class C1, only of the class C2 which he already loaded and he will try to load the dll from the current directory (the directory of the running assembly - not A or B, but you program which inspects B). If the “A.dll” is not located there he will try in GAC and if that fails he will throw an exception. How do you fix this? Well you have the choice to copy the “A.dll” in your running directory or registed in GAC but hell, it is not nice and sometimes not possible.
What you can do is to instruct the application domain to call a custom method defined by you when he needs to load an assembly.
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
Assembly ass =
Assembly.LoadFile(AppDomain.CurrentDomain.RelativeSearchPath + args.Name.Substring(0, args.Name.IndexOf(“,”)) + “.dll”);
return ass;
}
What I told the domain here is to call tyeh CurrentDomain_AssemblyResolve method and there I made an assumption. When you compile the namespace B, in it’s debug directory the dll of namespace A is also copied. So if you load the assembly of namespace b from it’s debug directory, in the same directory we will have also the assembly of A. So we will load the assembly from there
Simple and effective. This approach solves also the error “Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.”
Cheers



Entries (RSS)
July 14th, 2008 at 5:15 pm
You are a god. Thank you!
August 22nd, 2008 at 11:13 am
this is the exactly the problem i’m getting but i’m having trouble plugging your solution in. Where does the code go? Do you have a noddy demo source code for this
September 27th, 2008 at 9:27 am
You can plug it in the constructor of the class where you want to do the reflection.