C# 卸载.DLL需要帮助';来自AppDomain的s-即使使用卷影副本也无法工作

C# 卸载.DLL需要帮助';来自AppDomain的s-即使使用卷影副本也无法工作,c#,appdomain,shadow-copy,appdomainsetup,C#,Appdomain,Shadow Copy,Appdomainsetup,我正在努力做到以下几点。应用程序A是“母亲应用程序”。它一直开着。应用程序B只是一个.DLL,我在其中编写了一些从应用程序a中指定的接口派生的类 然后,从应用程序A,我将从应用程序B“导入”类,并在其中运行方法。我希望能够动态更改应用程序B(更改代码并重新编译),并在应用程序A中使用新代码 我在App B中有一个post-compile命令,它将新的.DLL复制到App a目录。应用程序A创建新的AppDomain并使用阴影复制。我原以为这就足够了,但当我尝试重新编译和复制AppB的新.DLL时

我正在努力做到以下几点。应用程序A是“母亲应用程序”。它一直开着。应用程序B只是一个.DLL,我在其中编写了一些从应用程序a中指定的接口派生的类

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

我在App B中有一个post-compile命令,它将新的.DLL复制到App a目录。应用程序A创建新的AppDomain并使用阴影复制。我原以为这就足够了,但当我尝试重新编译和复制AppB的新.DLL时,它说该文件正在使用中,无法覆盖

以下是我目前拥有的代码:

应用程序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++;
            }
        }   
    }   
}
namespace TestClient
{    
    public class TestRunner : TestServer.IRunnable
    {
        public void Run()
        {
            Console.WriteLine("RUNNING");
        }
    }

    public class Bob : TestServer.IRunnable
    {
        public void Run()
        {
            Console.WriteLine("BOB");
        }
    }
}
应用程序B(代码中的TestClient):

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++;
            }
        }   
    }   
}
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,从而将其锁定

如何解决此问题/是否有更好的设置


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

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

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

更新


根据这里提供的解决方案,运行程序的实例化将发生在DomainLifetimeHook的继承器中。所示的基础结构确保启动和停止方法在类AppDomainExpander创建的AppDomain中运行。该扩展器是创建新域的类,因此您的域设置应该使用域的Create方法。

主要问题是您在哪里执行以下操作:

Type type = assm.GetType("TestClient." + typeName);
这发生在应用程序A的主AppDomain中,结果是主AppDomain锁定了应用程序B的assembly.dll


flq对其博客文章的回答中的链接应该适合您。

一旦您打开ObjectHandle,必须将该类型加载到主appdomain中。要正常工作,您需要对未展开的ObjectHandle进行操作。

我将检查您的链接并报告。我主要关心的是在A运行时编写一些代码,然后让A执行新代码。这对你的方法有用吗?如果不是,我是想用正确的方式来做这件事,还是应该考虑其他的事情?我明白了。我会试试看。感谢flq的帮助!我已经更新了代码,但没有成功。你知道为什么吗?我不认为我在主AppDomain中调用了任何东西,但我显然可能弄错了。这应该是有用的:好吧,我决定努力破解它,一劳永逸地解决这个问题。这个解决方案远不优雅,但它确实有效。基本上,每次输入新名称时,我都会用不同的名称复制dll,加载并使用它。最后,我尝试删除它们(如果它们没有被锁定)。现在解决我的问题,直到我成为一个更好的程序员。Unwrap()将代理返回给另一个AppDomain中的对象,因此(不一定)不需要定义要加载到主AppDomain中的类型的程序集。