使用时交换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
        }

使用时交换DLL

通常需要卸载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");

您不应该直接引用主应用程序中的插件。将它们放在单独的项目中,并通过接口引用它们。