【问题标题】:How to unload assemblies from the GAC?如何从 GAC 中卸载程序集?
【发布时间】:2010-12-14 13:44:35
【问题描述】:

我正在尝试对特定产品运行自动化测试。 测试包括将产品安装到硬盘上的不同位置,然后对其执行一些操作,然后关闭应用程序。

启动进程的代码如下所示:

using (Process process = new Process())
            {
                process.StartInfo.FileName = "C:\mylocation\myapp.exe";
                process.Start();
            }

在连续执行测试时,当应用程序的安装位置发生变化时,我从上面的代码中得到一个异常:

API 限制:程序集 'file:///C:\alternate_location\myapp.exe' 已经从另一个加载 地点。它不能从 同一个新位置 应用程序域。

因此无法连续运行测试。

可以做些什么来克服这个问题?无论如何我可以从 GAC 中卸载程序集吗?

我可以在我的测试应用程序中做一些事情来克服这个问题吗?或者我正在测试的应用程序中是否必须进行一些更改?

【问题讨论】:

  • 顺便说一句,您没有将内容“加载”到 GAC 中,而是“注册”或“添加”。因此,您不会“卸载”,而是“删除”(因此 Konamiman 的回答很混乱)
  • 好的。谢谢指正。
  • 你用的是什么测试框架?
  • 测试框架是我正在开发的。

标签: .net assemblies clr appdomain


【解决方案1】:

一旦加载,您就无法从应用程序域中卸载程序集。但是您可以创建一个新的应用程序域 (AppDomain class),在其中加载程序集,使用它们,然后卸载该域。见这里:Good example of use of AppDomain

【讨论】:

  • 这与 AppDomains 无关。她指的是 GAC
  • +1er能否解释一下答案的相关性? (如果有充分的理由,我将删除我的 cmets 和/或 -1...)
  • 重新阅读问题,它与 AppDomains 完全有关,与 GAC 关系不大。可悲的是,撤​​消我的 -1 为时已晚...有人可以提出 +1 撤消吗:P
  • 您可以对我对其他问题的任何回答 +1 以进行补偿,尽管我不知道这在 SO 中是否被认为是合法/道德的 :-)
  • 那么你是建议我在单独的应用程序域中运行每个测试用例或类似的东西吗?
【解决方案2】:

向 GAC 添加某些内容不是组件定义的固有部分 - 它通常由安装程序等完成。

gacutil 工具可用于从 GAC 中删除您的工具。在 1.1 中,它位于 Framework 目录中。在较新的版本中,它在 SDK 中,例如,C:\Program Files (x86)\Microsoft Visual Studio 8\SDK\v2.0\Bin

【讨论】:

  • 但是,我会在每个测试用例之后卸载应用程序。 (否则我将不允许安装它的另一个副本)如果安装将程序集添加到 GAC,卸载是否也应该删除它?此外,在手动进行测试时,我似乎无法重现该问题。所以这似乎是一个时间问题。那么您是否建议在每个测试用例之后使用该工具从 GAC 中删除程序集?这对我来说可能不可行,因为我在只安装了 .NET 框架的机器上运行测试。 (没有VS和SDK)还有其他出路吗?
  • 听起来这里有很多混乱。你确定你把东西放进了GAC?您遇到的异常与尝试将相同的 DLL 从不同位置两次加载到同一个 AppDomain 中有关 - 这可能是由于多个测试在同一个 [AppDomain] 上下文中运行。 Konamiman的回答是正确的。您应该扩展您的问题以解释您用于执行测试的框架/机制 - 这将是找出适当隔离彼此执行的最佳方法的关键。当您说“安装”时,安装工具是什么意思?微星?
  • 对不起。这是正在发生的事情。我有一个测试应用程序一个接一个地执行测试用例。测试用例基本上是一个类的方法。这些测试旨在测试产品的安装人员。因此,每个测试用例都使用 InstallShield 安装程序安装产品,然后为了验证,我使用问题中描述的方法启动应用程序(已安装)。我做了一些基本操作,然后关闭应用程序并卸载它。下一个测试用例重复同样的事情,只是应用程序安装到另一个位置。 ...继续
  • 继续...在这种情况下,我得到了异常。我不是故意将东西放入 GAC。
  • @Poulo:那么我建议从您的问题中删除 GAC 这个词。听起来问题在于您正在将 .NET 类动态加载到您的测试应用程序中。这个程序集永远留在你的 appdomain 中,没有办法卸载它。解决方法是确保您加载到单独的应用程序域[完成后将其卸载],或者将其转至另一个 EXE,达到相同的结果。这正是Konamiman所说的,所以给他+1(但我认为那是你)!
【解决方案3】:

您能否为我们提供更多信息?我无法重现此错误。

Process.Start 应该使用自己的 AppDomain 创建一个新进程。

在我的机器上,我创建了一个项目 Harness,它有一个对 DoNothing 的项目引用,它是一个强签名的程序集,还有一个对 LaodDoNothing 的项目引用,它引用了 c:\DoNothing.exe。我从 Harness.Main 粘贴了下面的代码,其中调试输出为内联 cmets。后缀为 unsigned 的 exe 没有签名。

//debug outputs when Main is jitted:'Harness.vshost.exe' (Managed): Loaded 'c:\project\DoNothing\Harness\bin\Debug\DoNothing.exe', Symbols loaded.
//debug outputs when Main is jitted:'Harness.vshost.exe' (Managed): Loaded 'c:\project\DoNothing\Harness\bin\Debug\LoadDoNothing.exe', Symbols loaded.

ZaZaZa.Main();
LoadDoNothing.Program.Main();
using (Process process = new Process())
{
    process.StartInfo.FileName = @"C:\donothingunsigned.exe";
    process.Start(); //debug outputs The thread 0x17f0 has exited with code 0 (0x0).  No assemblies loads are logged to debug because this is a separate process.


}

using (Process process = new Process())
{
    process.StartInfo.FileName = @"C:\3\donothingunsigned2.exe";
    process.Start(); //Debug outputs The thread 0x1014 has exited with code 0 (0x0). No assemblies loads are logged to debug because this is a separate process.
}
AppDomain.CurrentDomain.ExecuteAssembly(@"C:\donothingunsigned.exe"); //debug outputs 'Harness.vshost.exe' (Managed): Loaded 'C:\donothingunsigned.exe'
AppDomain.CurrentDomain.ExecuteAssembly(@"C:\3\donothingunsigned2.exe"); //no debug output because the loader realizes this assembly has already been loaded and uses that.

【讨论】:

  • 我没有完全理解你想要表达的意思。但我确实注意到您已经启动了两个不同的可执行文件“donothingunsigned.exe”和“donothingunsigned2.exe”。我的问题与尝试从不同位置启动相同的可执行文件有关。这就是我在问题中以及后来的 cmets 中提到的情况下给我的例外情况。
  • 我无法使用上述方法重现错误。进程不共享应用程序域,所以我看不出 Process.Start() 如何导致您的错误。
猜你喜欢
  • 1970-01-01
  • 2011-01-27
  • 2011-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多