从 AppDomain 卸载 .DLL 需要帮助 - 即使使用 ShadowCopy 仍无法正常工作

Posted

技术标签:

【中文标题】从 AppDomain 卸载 .DLL 需要帮助 - 即使使用 ShadowCopy 仍无法正常工作【英文标题】:Help needed with unloading .DLL's from AppDomain - Still not working even with ShadowCopy 【发布时间】:2011-02-17 21:06:11 【问题描述】:

我正在尝试执行以下操作。应用 A 是“母应用”。它保持打开状态。 App B 只是一个 .DLL,我在其中编写了一些从 App A 中指定的接口派生的类。

然后,从 App A 中,我将从 App B 中“导入”类并在其中运行方法。我希望能够动态更改 App B(更改代码并重新编译)并在 App A 中使用新代码。

我在 App B 中有一个后编译命令,它将新的 .DLL 复制到 App A 目录。应用 A 创建一个新的 AppDomain 并使用 ShadowCopying。我认为这已经足够了,但是当我尝试重新编译和复制 App B 的新 .DLL 时,它说该文件正在使用中并且无法被覆盖。

这是我现在拥有的代码:

App A(代码中的TestServer):

namespace TestServer

    public interface IRunnable
    
        void Run();        
    

    class Program
            
        static void Main(string[] args)
        
            AppDomainSetup setup = new AppDomainSetup();
            setup.ApplicationName = "DemoApp";
            setup.ApplicationBase = Environment.CurrentDirectory;
            setup.ShadowCopyDirectories = Environment.CurrentDirectory;
            setup.ShadowCopyFiles = "true";
            int _domain = 1;

            while (true)
            
                string typeName = Console.ReadLine();

            AppDomain appDomain = AppDomain.CreateDomain("DemoDomain" + _domain, null, setup);

            IRunnable runner = appDomain.CreateInstanceFromAndUnwrap("TestClient.dll", typeName) as IRunnable;

            runner.Run();

            AppDomain.Unload(appDomain);
            _domain++;
            
           
       

App B(代码中的TestClient):

namespace TestClient
    
    public class TestRunner : TestServer.IRunnable
    
        public void Run()
        
            Console.WriteLine("RUNNING");
        
    

    public class Bob : TestServer.IRunnable
    
        public void Run()
        
            Console.WriteLine("BOB");
        
    

我已经读到,如果您使用来自其他应用程序域的东西,这些应用程序域可以自动加载 .DLL 或类似的东西。在这种情况下,我担心使用接口会导致基础 AppDomain 加载 .DLL 从而将其锁定。

我该如何解决这个问题/有更好的设置吗??

注意:我已经更新了我的代码,它仍然产生相同的结果。

【问题讨论】:

这应该很有用:social.msdn.microsoft.com/Forums/en-US/clr/thread/… 好吧,我决定努力破解它,一劳永逸地解决这个问题。这个解决方案远非优雅,但它有效。基本上,每次我输入一个新名称时,我都会用不同的名称复制 dll,加载并使用它。最后,我尝试删除它们(如果它们没有被锁定)。暂时解决我的问题,直到我成为更好的程序员 【参考方案1】:

您的代码仍在母 AppDomain 中运行,因为您将程序集和类型拉入其中。任何代码都应该在生成的域中运行。我已经展示了一种在我的网站上设置类似内容的方法:A simple way to start your code in a different AppDomain

我不是 100% 确定这一点,但这肯定是你必须采取的一步

更新

就那里提出的解决方案而言,跑步者的实例化将发生在 DomainLifetimeHook 的继承者中。显示的基础结构确保 Start 和 Stop 方法在由 AppDomainExpander 类创建的 AppDomain 中运行。该 Expander 是创建新域的类,因此您的域设置应该放在域的 Create 方法中。

【讨论】:

我会检查你的链接并报告回来。干杯 我主要关心的是能否在 A 运行时编写一些代码,然后让 A 执行新代码。这适用于您的方法吗?如果不是,我是在尝试以正确的方式做到这一点,还是应该考虑其他事情? 我明白了。我会试试看。感谢flq的帮助!【参考方案2】:

主要问题是你在哪里做:

Type type = assm.GetType("TestClient." + typeName);

这发生在 App A 的主 AppDomain 中,结果是主 AppDomain 锁定了 App B 的程序集 .dll

flq 对他的博客文章的回答中的链接应该对你有用。

【讨论】:

我已经更新了代码但没有成功。任何想法为什么?我不认为我在主 AppDomain 中调用了任何东西,但我显然可能弄错了。【参考方案3】:

在您打开 ObjectHandle 后,该类型必须加载到主应用程序域中。要正常工作,需要对未解包的ObjectHandle进行操作。

【讨论】:

不,它没有。 Unwrap() 返回另一个 AppDomain 中对象的代理,因此不需要(必然)需要定义要加载到主 AppDomain 中的类型的程序集。

以上是关于从 AppDomain 卸载 .DLL 需要帮助 - 即使使用 ShadowCopy 仍无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章

即使我卸载 appdomain,我的 dll 也不会卸载

AppDomain 卷影副本 - 加载/卸载动态加载的 Dll

使用AppDomain进行动态加载和卸载dll

卸载后 AppDomain 和使用的 DLL 的问题

C# AppDomain 无法加载 DLL

AppDomain 详解二-C#中动态加载和卸载DLL