2
votes

I've been having some major problems with executing .NET assemblies via C#. I want to invoke a static method (Main), from a static class. I had it working in the current domain, but apparently I can't unload the assemblies from there.

Firstly, I tried creating a new AppDomain:

AppDomain domain = AppDomain.CreateDomain("PluginDomain");

Since my main issue is with resolving the assemblies I'm trying to load, I tried to hook the AssemblyResolve event:

domain.AssemblyResolve += new ResolveEventHandler(this.OnAssemblyResolve);

However, I get an error about serialization with this (ie. the this class).

I have successfully loaded an assembly file which happens to be located in the BaseDirectory by simply using:

domain.Load("Assembly1");

But the problematic assembly is located within two subdirectories of the BaseDirectory, ie. BaseDirectory\dir1\dir2\Assembly2.dll - I get a FileNotFoundException when using domain.Load() with a string assembly name (with a PrivateBinPath setup to the correct subdirectory location) and also when using domain.Load() with the assembly bytes (from File.ReadAllBytes()).

I am aware that AppDomain.Load() is deprectated, but it seemed like the only useable method to me, considering that I don't want to force the class containing a static method to be non-static and instantiatable.

Anyway, what can I do to ensure the assembly file is loaded into the new AppDomain correctly?

My main objective with this, is to dynamically execute a method from an assembly which can make calls into my own program, yet the assembly must also be unloaded completely when necessary. It's intended to be somewhat of a plugin system.

1
Additionally, it appears the specific call you are invoking AppDomain.Load is not deprectated/obsolete even in .Net 4.5.Erik Philips
i see, the intelisense documentation made me think so, it tells me "[deprecated]". also, i'm not sure if this is a duplicate or not, but i couldn't resolve my problem from your answer in that thread - i had already tried configuring the assembly probe paths of AppDomainSetup for the new domain (as noted), and i couldn't make sense of the other option you gave when looking at my scenario.mina

1 Answers

5
votes

Event handler of Assembly.AssemblyResolve must be in the same AppDomain, where this assembly should be loaded. This is because this handler must return reference to instance of Assembly, but as soon as you have reference to assembly, it is automatically loaded so assembly would load in both AppDomains.

I suggest you to create small separate assembly in the same directory as the main application. This assembly would contain only one helper class derived from MarshalByRefObject, that can handle assembly resolving/loading, and can provide calling desired static method of plugin. Load this assembly to each AppDomain where you want load plugin, create instance of hepler class and call it.

public class HelperClass: MarshalByRefObject
{
    public void LoadPlugin(string PluginFileName)
    {
        //Load plugin assembly or register handler for Assembly.AssemblyResolve
        //AppDomain.CurrentDomain.Load()
        //AppDomain.CurrentDomain.AssemblyResolve += ...
        //Call plugin's static method
    }
}


AppDomain domain = AppDomain.CreateDomain("PluginDomain");
domain.Load("plugin_helper.dll");
HelperClass helper = (HelperClass)domain.CreateInstanceAndUnwrap("plugin_helper.dll", "HelperClass");
helper.LoadPlugin("plugin1.dll");