使用时交换DLL
本文关键字:DLL 交换 | 更新日期: 2023-09-27 18:29:41
我正在构建一个插件类型的系统,每个插件都表示为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
}
通常需要卸载AppDomain进行通信。如果你想防止上述错误,你只需使用Assembly.Load(Byte[])
加载你的dll。
您还可以使用托管扩展性框架,这将为您节省大量工作。
Assembly.Load问题解决方案
在远程计算机上使用Assembly.LoadFrom()加载的程序集导致SecurityException
将插件DLL加载到另一个AppDomain是唯一的解决方案,因此您走的是正确的道路。注意对象是否从第二个应用程序域泄漏到主应用程序域。你需要在插件的AppDomain中进行所有与插件的通信。
也就是说,将插件的对象返回到主代码可能会将插件的Assembly用法泄漏到主AppDomain。
从非常简单的代码开始,完全在插件的AppDomain中,比如"加载程序集并创建类,但不向主域返回任何内容"。当你对AppDomains之间的通信有了更多的了解时,就可以扩大使用范围了。
注意:除非你是为了教育目的而使用现有的系统(即MEF)更好。
你可以这样做。。。
if (pluginAppDomain != null)
{
AppDomain.Unload(pluginAppDomain);
}
//for each plugin
pluginAppDomain = AppDomain.CreateDomain("Plugins Domain");
x = pluginAppDomain.CreateInstanceFromAndUnwrap("Plugin1.dll", "Namespace.Type");
您不应该直接引用主应用程序中的插件。将它们放在单独的项目中,并通过接口引用它们。