基于GAC内容设置的.NET参考“复制本地”真/假

时间:2010-03-20 00:54:27

标签: .net assemblies reference log4net gac

我们在Win Forms项目中遇到了一个非常有趣的问题。它已经解决了。我们知道发生了什么,但我们想知道它为什么会发生。这可能有助于将来遇到类似问题的其他人。

WinForms项目在我们客户的两台PC上失败了。该错误是一个模糊的kernel.dll错误。该项目在其他3台PC上运行良好。

我们发现我们的发布文件夹中缺少.DLL(log4net.dll - 一个非常流行的开源日志库)。它以前在我们的发布文件夹中。为什么在最新版本中缺少它?

它丢失了,因为我必须在我的开发盒上安装了一个程序,该程序使用了log4net.dll,并且它被添加到全局程序集缓存中。

当我检查解决方案对log4net.dll的引用时,它们被更改为“copy local = FALSE”。它们必须自动更改,因为我的GAC中存在log4net.dll。

以下是我的问题所在:

为什么我对log4net.dll的引用从COPY LOCAL = TRUE更改为COPY LOCAL = FALSE?我怀疑是因为它是由另一个程序添加到我的GAC中的。

我们怎样才能防止这种情况再次发生?按照现在的情况,如果我安装了一个使用公共库并将其添加到我的GAC的软件,那么引用该DLL的我的SLN将从Copy Local TRUE更改为FALSE。

5 个答案:

答案 0 :(得分:6)

之所以发生这种情况,是因为如果在GAC中安装了程序集,则Copy Local = True没有任何意义。由于永远不会使用本地副本,因此始终首先搜索GAC。保持不变会导致严重的混乱,你会认为你正在使用本地副本而是另外一个。如果您没有注意到它,更改它也会导致混淆,这可能是在解决方案加载时使用消息框解决的。

Log4net是一个麻烦制造者,在野外有太多版本,没有任何部署程序可以确保这些版本不相互咬合。 Apache显然只是不想解决的事情,而是由程序员决定。拥有依赖于Log4net的产品并对感知的DLL Hell风险做一些事情在某种程度上是不可避免的。给你一个DLL地狱问题作为回报。

除了了解机器上安装的内容之外,没有简单明了的答案。当Visual Studio自动更新“复制本地”属性时,请考虑发布到connect.microsoft.com以请求警告。这是一个合理的问题。

答案 1 :(得分:3)

我在构建服务器上找到了解决方案。

问题: 在没有任何理由的特定日期(我现在假设该文件已添加到GAC),程序集System.Web.MVC.dll从我们的许多项目中消失了。我确信这适用于任何有问题的dll。

解决方案: 在visual studio中更改引用(假设Copy Local已经为True)。

  1. 将Copy Local = True更改为Copy Local = False
  2. 将本地复制更改为True
  3. 请注意.csproj文件中添加了<Private>True</Private>
  4. 现在编译,即使消息保持不变,您也会看到dll确实包含在内。
  5. 溶液2: 手动添加<private>True</private>属性。

    结论: 我对<Private>的理解是复制本地,所以如果Copy Local = True,应该添加私有属性,但在我们的情况下,至少它不是。

    其他注意事项:

    1. 使用Visual Studio 2013和2015进行测试。
    2. 使用msbuild 12和14进行测试。
    3. 使用TFS构建模板进行测试。
    4. 我们的代码已经从2008年升级到2015年的视觉工作室,该标志可能在那个时间某个地方搞砸了,但问题没有开始,直到大会以某种方式添加到GAC。
    5. 结束结果:

      <Reference Include="System.Web.Mvc, Version=4.0.0.1, Culture=neutral,PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
      <SpecificVersion>False</SpecificVersion>
       <HintPath>packages\Microsoft.AspNet.Mvc.4.0.40804.0\lib\net40\System.Web.Mvc.dll        </HintPath>
              <Private>True</Private>
          </Reference>
      

答案 2 :(得分:2)

在运行时,程序集必须位于以下两个位置之一:项目的输出路径或全局程序集缓存(请参阅使用程序集和全局程序集缓存)。如果项目包含对不在其中一个位置的对象的引用,则在构建项目时,必须将引用复制到项目的输出路径。 CopyLocal属性指示是否需要创建此副本。如果值为true,则复制引用。如果为false,则不复制引用。

CopyLocal的项目指定值按以下顺序确定:

  1. 如果引用是另一个项目,称为项目到项目引用,则该值为true。
  2. 如果在全局程序集缓存中找到程序集,则该值为false。
  3. 作为一种特殊情况,mscorlib.dll引用的值为false。
  4. 如果在Framework SDK文件夹中找到程序集,则该值为false。 否则,该值为true。
  5. ...问候 Muse VSExtensions

答案 3 :(得分:1)

我刚刚在构建服务器上遇到了这个问题。这是Visual Studio非常烦人(和意外)的行为。两个解决方法:

  1. 从GAC中删除程序集。
  2. 添加PostBuild事件以手动将程序集复制到输出目录中。

答案 4 :(得分:0)

你可以通过在msbuild / proj文件中添加hintpath来确保使用你的吗?

从以上链接:

HintPath :程序集的相对或绝对路径