我正在构建一个插件类型系统,每个插件都表示为DLL。我希望能够在不停止主应用程序的情况下重新加载它们。这意味着它们必须在运行时加载,而不需要在它们之间预先建立链接(对dll执行文件搜索并加载它们)。我使用Assembly.LoadFile(filename)
进行了此设置,但是,当我尝试使用File.Copy
来替换DLL时,它会抛出一个异常,说出类似于'文件正在使用的内容'。我已经尝试使用AppDomain
,通过这个辅助域加载所有插件,并在重新加载之前卸载它,但这会引发相同的异常。
我目前的代码:
if (pluginAppDomain != null)
AppDomain.Unload(pluginAppDomain);
foreach (string s in Directory.GetFiles(path_to_new_DLLs))
{
string name = s.Substring(s.LastIndexOf('\\') + 1);
Console.WriteLine("Copying " + name);
File.Copy(s, Path.Combine(current_directory, name), true); // Throws exception here
}
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = Environment.CurrentDirectory;
setup.ShadowCopyFiles = "true";
// I think this is where the problem is, maybe I'm forgetting to set something
pluginAppDomain = AppDomain.CreateDomain("KhybotPlugin", null, setup);
foreach (String s in Directory.GetFiles(Environment.CurrentDirectory, "*.dll"))
{
int pos = s.LastIndexOf('\\') + 1;
Assembly dll = pluginAppDomain.Load(s.Substring(pos, s.Length - pos - 4));
// Elided... Load types from DLL, etc, etc
}
答案 0 :(得分:5)
通常,您需要卸载AppDomain以进行通信。
如果您想阻止上述错误,只需使用Assembly.Load(Byte[])
加载您的dll即可。
您还可以使用Managed Extensibility Framework,这将为您节省大量工作。
Assembly loaded using Assembly.LoadFrom() on remote machine causes SecurityException
答案 1 :(得分:2)
将插件DLL加载到另一个AppDomain是唯一的解决方案 - 因此您走在正确的道路上。注意从第二个应用程序域到主要域的泄漏对象。您需要在插件的AppDomain中进行与插件的所有通信。
即。将插件的对象返回到主代码可能会将插件的程序集使用泄漏到主AppDomain。
从插件的AppDomain中完全开始使用非常简单的代码,例如“加载程序集和创建类,但不要向主域返回任何内容”。当您更加了解AppDomains之间的通信时,请扩展使用范围。
注意:除非您出于教育目的使用现有系统(即MEF)做得更好。
答案 2 :(得分:0)
你可以这样做......
if (pluginAppDomain != null)
{
AppDomain.Unload(pluginAppDomain);
}
//for each plugin
pluginAppDomain = AppDomain.CreateDomain("Plugins Domain");
x = pluginAppDomain.CreateInstanceFromAndUnwrap("Plugin1.dll", "Namespace.Type");
您不应直接在主应用中引用插件。将它们放在单独的项目中,并通过接口引用它们。