从 AppDomain 卸载 .DLL 时需要帮助 - 即使使用 ShadowCopy 仍然无法工作
我正在尝试执行以下操作。应用程序 A 是“母应用程序”。它保持开放状态。应用程序 B 只是一个 .DLL,我在其中编写了一些从应用程序 A 中指定的接口派生的类。
然后,从应用程序 A 中,我将从应用程序 B 中“导入”类并运行其中的方法。我希望能够动态更改应用程序 B(更改代码并重新编译)并在应用程序 A 中使用新代码。
我在应用程序 B 中有一个编译后命令,可将新的 .DLL 复制到应用程序 A 目录。应用程序 A 创建一个新的应用程序域并使用 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 或类似的东西。在这种情况下,我担心使用 Interface 会导致基础 AppDomain 加载 .DLL,从而将其锁定。
我该如何解决这个问题/有更好的设置吗?
注意:我已经更新了我的代码,但它仍然产生相同的结果。
I am trying to do the following. App A is the "mother app". It stays open. App B is just a .DLL where I write some classes that are derived from an interface specified in App A.
Then, from App A, I will "import" classes from App B and run methods within them. I want to be able to dynamically change App B (change code and recompile) and use the new code in App A.
I have a post-compile command in App B that copies the new .DLL to the App A directory. App A creates a new AppDomain and uses ShadowCopying. I thought this would be sufficient, but when I try to recompile & copy App B's new .DLL, it says that the file is in use and can't be overwritten.
Here is the code I have as of now:
App A (TestServer in code):
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 in code):
namespace TestClient
{
public class TestRunner : TestServer.IRunnable
{
public void Run()
{
Console.WriteLine("RUNNING");
}
}
public class Bob : TestServer.IRunnable
{
public void Run()
{
Console.WriteLine("BOB");
}
}
}
I have read that if you use stuff from other app domains, those app domains could automatically load the .DLL or something along those lines. In this case, I fear that using the Interface is causing the base AppDomain to load the .DLL thereby locking it up.
How can I resolve this issue / is there a better setup??
NOTE: I have update my code and it still yields the same result.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
当您将程序集和类型拉入其中时,您的代码仍然在母 AppDomain 中运行。任何代码都应该在生成的域中运行。我已经在我的网站上展示了一种设置类似内容的方法: 一种在不同 AppDomain 中启动代码的简单方法
我对此不是 100% 确定,但这肯定是您必须采取的一个步骤
更新
根据此处提供的解决方案,运行程序的实例化将发生在 DomainLifetimeHook 的继承者中。显示的基础结构确保 Start 和 Stop 方法在 AppDomainExpander 类创建的 AppDomain 中运行。 Expander 是创建新域的类,因此您的域设置应该进入域的 Create 方法。
Your code still runs in the mother AppDomain, as you're pulling in assemblies and types into there. Any code should run in the spawned domain. I've shown one way to set something like that up on my website : A simple way to start your code in a different AppDomain
I'm not 100% sure on that but that's certainly one step you'll have to undertake
Update
In terms of the solution presented there, your instantiation of a runner would happen in an inheritor of DomainLifetimeHook. The infrastructure shown ensures that the Start and Stop methods run in the AppDomain created by the class AppDomainExpander. That Expander is the class that creates the new domain, hence your domain setup should go in the Create method of the domain.
主要问题在于您的操作位置:
这种情况发生在应用程序 A 的主应用程序域中,结果是主应用程序域锁定了应用程序 B 的程序集 .dll
flq 对其博客文章的回答中的链接应该适合您。
The main problem is where you do:
This is happening in App A's main AppDomain, and the consequence is that the main AppDomain locks App B's assembly .dll
The link in flq's answer to his blog post should work for you.
一旦您解开 ObjectHandle,该类型就必须加载到主应用程序域中。为了正常工作,您需要对未解包的 ObjectHandle 进行操作。
The type has to be loaded into the main appdomain as soon as you unwrap the ObjectHandle. To work properly, you need to operate on the non-unwrapped ObjectHandle.