1

I'm working on a sort of plugin system for a Discord bot. Right now i'm on macOS using Mono as my runtime and I've been looking at using seperate AppDomains to load and manage each of the plugins. The plugins themselves do have dependencies but these are already loaded in the main appdomain. So here lies my problem:

  1. I've attempted to iterate over the loaded assemblies in the current domain and load them into my separate AppDomain so the plugin's dependencies are already loaded in. This results in a FileNotFoundException when trying to load said dependencies (even though I point them to the correct path in the exe directory).

  2. I've tried without doing that and just going through and loading the plugin dll's into a separate AppDomain and seeing if it'll resolve automatically. Still throws a FileNotFoundException.

  3. I tried manually creating an array in order of the dependendies (in my application's case, Newtonsoft.Json -> DSharpPlus -> Bot.CommandManager). I can't even load Newtonsoft.Json due to a missing dependency.

  4. Now, I'm loading the raw bytes into a stream reader and passing that into AppDomain.Load to make sure that the FileNotFoundException comes from a lack of dependency and not the actual file being missing. The file is there, still throws FileNotFoundException on domain.Load

The only way I've been able to successfully load the plugins is just using Assembly.Load and not worrying about AppDomains which works great until I update something and want to unload/reload the plugin. Which is where I need to use AppDomain. I'm kind of lost, here's my current iteration of the code. It's probably extremely unnecessary to have a separate AppDomain for each plugin but I'm rolling with that for now.

private void SetupAppDomain()
    {
        string path = Directory.GetCurrentDirectory() + "/modules/";
        Console.WriteLine(path);
        List<string> installedModules = new List<string>();
        string[] files = Directory.GetFiles(path);
        foreach(string modulePath in files)
        {
            try
            {
                AppDomain domain = AppDomain.CreateDomain(Path.GetFileName(modulePath), AppDomain.CurrentDomain.Evidence);
                StreamReader reader = new StreamReader(modulePath, System.Text.Encoding.GetEncoding(1252), false);
                byte[] b = new byte[reader.BaseStream.Length];
                reader.BaseStream.Read(b, 0, System.Convert.ToInt32(reader.BaseStream.Length));
                domain.Load(b); //this throws the FileNotFoundException
                Assembly[] a = domain.GetAssemblies();
                int index = 0;
                for (int i = 0; i < a.Length; i++)
                {
                    if(a[i].GetName().Name + ".dll" == Path.GetFileName(modulePath))
                    {
                        index = i;
                        break;
                    }
                }
                installedModules.Add(a[index].GetName().Name);
            }
            catch(Exception ex)
            {
                throw ex;
            }
        }
    }

Worst case scenario, I can just go back to the old way of doing it and just have to restart the bot when I want to reload assemblies.

MrMiketheripper
  • 133
  • 1
  • 10
  • I found this one: https://stackoverflow.com/questions/11989896/load-assemblies-with-dependencies-in-a-different-appdomain#12009335 ```domain.AssemblyResolve``` not sure if it works on mono – FrankM Jan 26 '18 at 14:55
  • AppDomains in C# mono are unsupported. You cannot load dlls in a separate appdomain. See if this fits what you are looking for and I'll post it as an answer: https://stackoverflow.com/questions/54281115/appdomain-support-is-dead-in-unityengine-any-way-to-unload-dll/58640188 – DreTaX Nov 02 '19 at 10:07

0 Answers0