How Do I Load an Assembly and All of its Dependencies at Runtime in C# for Reflection?
Asked Answered
A

2

18

I'm writing a utility for myself, partly as an exercise in learning C# Reflection and partly because I actually want the resulting tool for my own use.

What I'm after is basically pointing the application at an assembly and choosing a given class from which to select properties that should be included in an exported HTML form as fields. That form will be then used in my ASP.NET MVC app as the beginning of a View.

As I'm using Subsonic objects for the applications where I want to use, this should be reasonable and I figured that, by wanting to include things like differing output HTML depending on data type, Reflection was the way to get this done.

What I'm looking for, however, seems to be elusive. I'm trying to take the DLL/EXE that's chosen through the OpenFileDialog as the starting point and load it:

String FilePath = Path.GetDirectoryName(FileName);
System.Reflection.Assembly o = System.Reflection.Assembly.LoadFile(FileName);

That works fine, but because Subsonic-generated objects actually are full of object types that are defined in Subsonic.dll, etc., those dependent objects aren't loaded. Enter:

AssemblyName[] ReferencedAssemblies = o.GetReferencedAssemblies();

That, too, contains exactly what I would expect it to. However, what I'm trying to figure out is how to load those assemblies so that my digging into my objects will work properly. I understand that if those assemblies were in the GAC or in the directory of the running executable, I could just load them by their name, but that isn't likely to be the case for this use case and it's my primary use case.

So, what it boils down to is how do I load a given assembly and all of its arbitrary assemblies starting with a filename and resulting in a completely Reflection-browsable tree of types, properties, methods, etc.

I know that tools like Reflector do this, I just can't find the syntax for getting at it.

Atli answered 12/9, 2008 at 15:7 Comment(0)
G
13

Couple of options here:

  1. Attach to AppDomain.AssemblyResolve and do another LoadFile based on the requested assembly.
  2. Spin up another AppDomain with the directory as its base and load the assemblies in that AppDomain.

I'd highly recommend pursuing option 2, since that will likely be cleaner and allow you to unload all those assemblies after. Also, consider loading assemblies in the reflection-only context if you only need to reflect over them (see Assembly.ReflectionOnlyLoad).

Guevara answered 12/9, 2008 at 15:13 Comment(1)
How to do option 2?Somato
A
6

I worked out Kent Boogaart's second option. Essentially I had to:

1.) Implement the ResolveEventHandler in a separate class, inheriting from MarshalByRefObject and adding the Serializable attribute.

2.) Add the current ApplicationBase, essentially where the event handler's dll is, to the AppDomain PrivateBinPath.

You can find the code on github.

Aceae answered 5/5, 2016 at 21:54 Comment(2)
You said MarshalByValueObject. Did you mean MarshalByRefObject?Celle
Oh, true, MarshalByRefObject.Aceae

© 2022 - 2024 — McMap. All rights reserved.