如果在解决方案中使用项目依赖项,MSBuild不会复制引用(DLL文件)

时间:2009-07-15 15:46:09

标签: visual-studio msbuild reference dependencies project

我的Visual Studio解决方案中有四个项目(每个人都针对.NET 3.5) - 对于我的问题,这两个项目很重要:

  1. MyBaseProject < - 此类库引用第三方DLL文件(elmah.dll)
  2. MyWebProject1 < - 此Web应用程序项目引用了MyBaseProject
  3. 我在Visual Studio 2008中添加了对 MyBaseProject 的elmah.dll引用,单击“添加引用...”→“浏览”选项卡→选择“elmah.dll”。

    Elmah参考文献的属性如下:

    • 别名 - 全球
    • 复制本地 - true
    • 文化 -
    • 描述 - 错误记录ASP.NET的模块和处理程序(ELMAH)
    • 文件类型 - 汇编
    • 路径 - D:\ webs \ otherfolder \ _myPath \ __ tools \ elmah \ Elmah.dll
    • 已解决 - 正确
    • 运行时版本 - v2.0.50727
    • 指定版本 - false
    • 强名称 - 假
    • 版本 - 1.0.11211.0

    MyWebProject1 中,我添加了对Project MyBaseProject的引用: “添加引用...”→“项目”选项卡→选择“MyBaseProject”。除以下成员外,此引用的属性相同:

    • 说明 -
    • 路径 - D:\ webs \ CMS \ MyBaseProject \ bin \ Debug \ MyBaseProject.dll
    • 版本 - 1.0.0.0

    如果我在 Visual Studio 中运行构建,则elmah.dll文件将与MyBaseProject.dll一起复制到我的 MyWebProject1的bin 目录中。

    但是,如果我清理并运行解决方案的 MSBuild (通过D:\ webs \ CMS> C:\ WINDOWS \ Microsoft.NET \ Framework \ v3.5 \ MSBuild.exe / t: ReBuild / p:Configuration = Debug MyProject.sln) 在MyWebProject1的bin目录中 elmah.dll缺失 - 虽然构建本身不包含警告或错误!

    我已经确定MyBaseProject的.csproj包含值为“true”的私有元素(它应该是Visual中“复制本地”的别名工作室):

    <Reference Include="Elmah, Version=1.0.11211.0, Culture=neutral, processorArchitecture=MSIL">
      <SpecificVersion>False</SpecificVersion>
      <HintPath>..\mypath\__tools\elmah\Elmah.dll</HintPath>
        **<Private>true</Private>**
    </Reference>
    

    (默认情况下私有标签没有出现在.csproj的xml中,虽然Visual Studio说“copy local”为true。我将“copy local”切换为false - 保存 - 并再次将其设置为true - 保存! )

    MSBuild有什么问题?如何将(elmah.dll)引用复制到MyWebProject1的bin?

    我不想在每个项目的postbuild命令中添加postbuild复制操作! (想象一下,我会有很多项目依赖于MyBaseProject!)

19 个答案:

答案 0 :(得分:166)

我只是像这样处理它。转到参考的属性并执行以下操作:

Set "Copy local = false"
Save
Set "Copy local = true"
Save

就是这样。

Visual Studio 2010最初并未放入:             引用标记中的<private>True</private>并将“copy local”设置为false会导致它创建标记。之后它将相应地设置为true和false。

答案 1 :(得分:143)

我不确定为什么在Visual Studio和MsBuild之间构建时会有所不同,但这是我在MsBuild和Visual Studio中遇到此问题时发现的内容。

说明

对于示例场景,假设我们有项目X,程序集A和程序集B.程序集A引用程序集B,因此项目X包含对A和B的引用。此外,项目X包含引用程序集A的代码(例如A.SomeFunction())。现在,您创建一个引用项目X的新项目Y。

因此依赖关系链如下所示: Y =&gt; X =&gt; A =&gt;乙

Visual Studio / MSBuild试图变得聪明,只将引用引入到项目Y中,它检测到项目X需要它;这样做是为了避免项目Y中的参考污染。问题是,由于项目X实际上不包含任何明确使用程序集B的代码(例如B.SomeFunction()),VS / MSBuild不会检测到B是必需的通过X,因此不会将其复制到项目Y的bin目录中;它只复制X和A程序集。

解决方案

您有两个选项可以解决此问题,这两个选项都会导致程序集B被复制到项目Y的bin目录中:

  1. 在项目Y中添加对程序集B的引用。
  2. 将虚拟代码添加到项目X中使用程序集B的文件中。
  3. 就个人而言,我个人更喜欢选项2。

    1. 如果您将来添加另一个引用项目X的项目,则不必记住还包含对程序集B的引用(就像您必须使用选项1一样)。
    2. 你可以有明确的评论说明为什么虚拟代码需要存在而不是删除它。因此,如果有人确实删除了代码(比如使用查找未使用代码的重构工具),您可以从源代码控制中轻松地看到代码是必需的并恢复它。如果您使用选项1并且某人使用重构工具来清理未使用的引用,则您没有任何注释;您将看到从.csproj文件中删除了引用。
    3. 以下是我遇到这种情况时通常会添加的“虚拟代码”示例。

          // DO NOT DELETE THIS CODE UNLESS WE NO LONGER REQUIRE ASSEMBLY A!!!
          private void DummyFunctionToMakeSureReferencesGetCopiedProperly_DO_NOT_DELETE_THIS_CODE()
          {
              // Assembly A is used by this file, and that assembly depends on assembly B,
              // but this project does not have any code that explicitly references assembly B. Therefore, when another project references
              // this project, this project's assembly and the assembly A get copied to the project's bin directory, but not
              // assembly B. So in order to get the required assembly B copied over, we add some dummy code here (that never
              // gets called) that references assembly B; this will flag VS/MSBuild to copy the required assembly B over as well.
              var dummyType = typeof(B.SomeClass);
              Console.WriteLine(dummyType.FullName);
          }
      

答案 2 :(得分:38)

如果您没有直接在代码中使用程序集,那么Visual Studio在尝试提供帮助时会检测到它未被使用,并且不会将其包含在输出中。我不确定为什么你会在Visual Studio和MSBuild之间看到不同的行为。您可以尝试将构建输出设置为两者的诊断,并比较结果,看看它的分歧。

对于你的elmah.dll引用,如果你没有直接在代码中引用它,可以将它作为项添加到项目中,并将Build Action设置为Content,将Copy to Output Directory设置为{{1 }}

答案 3 :(得分:14)

看看:

This MSBuild forum thread I started

你会在那里找到我的临时解决方案/解决方法!

(MyBaseProject需要一些引用elmah.dll中某些类(无论如何)的代码,以便将elmah.dll复制到MyWebProject1的bin中!)

答案 4 :(得分:8)

我遇到了同样的问题。

检查项目的框架版本是否与您引用的dll的框架版本相同。

就我而言,我的客户端是使用“Framework 4 Client”编译的,DLL是在“Framework 4”中。

答案 5 :(得分:6)

我遇到的问题是我有一个依赖于图书馆项目的项目。为了构建,我遵循了以下步骤:

msbuild.exe myproject.vbproj /T:Rebuild
msbuild.exe myproject.vbproj /T:Package

这当然意味着我在bin中丢失了我的库的dll文件,最重要的是在包zip文件中。我发现这很有效:

msbuild.exe myproject.vbproj /T:Rebuild;Package

我不知道为什么这项工作或为什么它首先没有。但希望有所帮助。

答案 6 :(得分:4)

正如Alex Burtsev在评论中提到的只在XAML资源字典中使用的任何内容,或者在我的情况下,任何仅在XAML中使用而不在代码中使用的内容,都不被MSBuild视为“正在使用”。

因此,简单地在一些代码后面对程序集中的类/组件进行虚拟引用就足以让MSBuild确信该程序集实际上正在使用中。

答案 7 :(得分:4)

我遇到了完全相同的问题,结果是由于同一解决方案中的2个项目引用了第三方库的不同版本。

一旦我纠正了所有参考文献,一切都工作得很好。

答案 8 :(得分:3)

使用致命狗的计划

Y =&gt; X =&gt; A =&gt; B

我的问题是当我构建Y时,来自X的程序集(A和B,所有15个)都没有出现在Y的bin文件夹中。

我通过从Y中删除引用X来解决它,保存,构建,然后重新添加X引用(项目引用),并保存,构建,并且A和B开始显示在Y的bin中文件夹中。

答案 9 :(得分:3)

将目标框架从 .NET Framework 4 Client Profile 更改为 .NET Framework 4 为我解决了这个问题。

因此在您的示例中:将MyWebProject1上的目标框架设置为 .NET Framework 4

答案 10 :(得分:2)

这需要在项目中添加.targets文件并将其设置为包含在项目的包含部分中。

有关程序,请参阅my answer here

答案 11 :(得分:2)

另一种情况是,如果您使用旧的&#34;网站&#34; Visual Studio中的项目类型。对于该项目类型,它无法引用其自身目录结构之外的.dll(当前文件夹和向下)。所以在上面的答案中,让我们说你的目录结构如下所示:

enter image description here

其中ProjectX和ProjectY是父/子目录,而ProjectX引用A.dll,后者又引用B.dll,而B.dll在目录结构之外,例如在根(包)上的Nuget包中,然后将包括A.dll,但B.dll不会。

答案 12 :(得分:2)

引用在构建期间未使用的程序集不是正确的做法。您应该扩充构建文件,以便复制其他文件。通过使用post build事件或更新属性组。

其他帖子中可以找到一些例子

答案 13 :(得分:2)

我有同样的问题,dll是一个动态加载的引用。 为了解决这个问题,我在dll的命名空间中添加了“using”。 现在,dll将复制到输出文件夹中。

答案 14 :(得分:0)

我今天遇到了类似的问题,这肯定不是你问题的答案。但我想告诉大家,并可能提供一些见解。

我有一个ASP.NET应用程序。构建过程设置为clean,然后构建。

我有两个Jenkins CI个脚本。一个用于生产,一个用于分期。我将我的应用程序部署到暂存,一切正常。部署到生产并丢失了引用的DLL文件。这个DLL文件就在项目的根目录中。不在任何NuGet存储库中。 DLL设置为do not copy

两个部署之间的CI脚本和应用程序是相同的。仍然在暂存环境中清理和部署之后,DLL文件在ASP.NET应用程序的部署位置(bin/)中被替换。生产环境并非如此。

事实证明,在测试分支中,我已经在构建过程中添加了一个步骤,将此DLL文件复制到bin目录。现在需要花一点时间来弄清楚的部分。 CI过程本身并没有清理。 DLL留在工作目录中,并且意外地与ASP.NET .zip文件打包在一起。生产分支从未以相同的方式复制DLL文件,并且从不会意外地部署它。

TLDR;检查并确保您知道构建服务器正在做什么。

答案 15 :(得分:0)

我遇到了一个非常类似的问题。使用Visual Studio 2010进行编译时,DLL文件包含在bin文件夹中。但是在使用MSBuild进行编译时,未包含第三方DLL文件。

非常令人沮丧。我解决它的方法是在我的web项目中包含NuGet对包的引用,即使我没有直接在那里使用它。

答案 16 :(得分:0)

请确保两个项目都使用相同的.net版本,并检查“复制本地”属性,但默认应为true

答案 17 :(得分:0)

使用Visual Studio 2015添加其他参数

  

/ deployonbuild = false

在msbuild命令行中解决了该问题。

答案 18 :(得分:-3)

在网站项目中包含项目引用中所有引用的DLL文件并不总是一个好主意,尤其是当您使用dependency injection时:您的Web项目只是想添加对接口DLL文件/项目的引用,没有任何具体的实现DLL文件。

因为如果直接向实现DLL文件/项目添加引用,则无法阻止开发人员在实现DLL文件/项目的具体类上而不是通过接口调用“new”。您也在网站上声明了使用该实施的“硬编码”。