我正在为Discord bot开发一种插件系统。现在我使用Mono作为我的运行时使用macOS,我一直在寻找使用单独的AppDomains来加载和管理每个插件。插件本身确实有依赖关系,但这些已经加载到主appdomain中。所以这就是我的问题:
我试图迭代当前域中加载的程序集并将它们加载到我的单独AppDomain中,因此插件的依赖项已经加载。这会在尝试加载所述依赖项时导致FileNotFoundException(即使我将它们指向exe目录中的正确路径。)
我试过没有这样做,只是通过将插件dll加载到一个单独的AppDomain中,看看它是否会自动解决。仍然会抛出FileNotFoundException。
我尝试按照dependendies的顺序手动创建一个数组(在我的应用程序的情况下,Newtonsoft.Json - > DSharpPlus - > Bot.CommandManager)。由于缺少依赖性,我甚至无法加载Newtonsoft.Json。
现在,我将原始字节加载到流读取器并将其传递到AppDomain.Load,以确保FileNotFoundException来自缺少依赖性而不是实际文件丢失。文件在那里,仍在domain.Load
我能够成功加载插件的唯一方法就是使用Assembly.Load
并且不要担心AppDomains在我更新内容并想要卸载/重新加载插件之前效果很好。这是我需要使用AppDomain的地方。我有点迷茫,这是我目前的代码迭代。对于每个插件都有一个单独的AppDomain可能是非常不必要的,但我现在正在使用它。
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;
}
}
}
最糟糕的情况是,我可以回到原来的做法,当我想重新加载程序集时只需要重新启动机器人。