在使用时交换DLL

时间:2012-04-02 16:27:53

标签: c# dll

我正在构建一个插件类型系统,每个插件都表示为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
        }

3 个答案:

答案 0 :(得分:5)

通常,您需要卸载AppDomain以进行通信。 如果您想阻止上述错误,只需使用Assembly.Load(Byte[])加载您的dll即可。

您还可以使用Managed Extensibility Framework,这将为您节省大量工作。

Assembly.Load问题解决方案

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");

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