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


273

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

  1. MyBaseProject <-该类库引用了第三方DLL文件(elmah.dll)
  2. MyWebProject1 <-此Web应用程序项目对MyBaseProject的引用

我加入了elmah.dll参考MyBaseProject通过点击在Visual Studio 2008中的“添加引用...”→“浏览”选项卡→选择“elmah.dll”。

《 Elmah参考》的属性如下:

  • 别名-全球
  • 复制本地-正确
  • 文化-
  • 说明-ASP.NET的错误记录模块和处理程序(ELMAH)
  • 文件类型-组装
  • 路径-D:\ webs \ otherfolder \ _myPath \ __ tools \ elmah \ Elmah.dll
  • 解决-正确
  • 运行时版本-v2.0.50727
  • 指定版本-否
  • 强名-错误
  • 版本-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 Studio中“ copy local ” 的别名):

<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>

(尽管Visual Studio说“ copy local”为true,但默认情况下,私有标签未显示在.csproj的xml中。我将“ copy local”切换为false-保存-再次将其设置为true-保存!)

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

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


11
对于这种情况的发生,我很想得到一个更明确的答案。
David Faivre 2012年


1
有完整源代码示例的最终解决方案吗?
Kiquenet

2
请参阅下面@deadlydog 的答案stackoverflow.com/a/21055664/21579。极好的解释,并为我解决了这个问题...以下投票最多的答案不适用于VS2012。
杰夫·威德默

Answers:


153

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

说明

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

因此依赖项链如下所示:Y => X => A => B

Visual Studio / MSBuild试图变得聪明,只将引用引入到项目Y中,它检测到项目X需要它;问题是,因为项目X实际上不包含任何明确使用程序集B的代码(例如B.SomeFunction()),所以VS / MSBuild不会检测到需要B X,因此不会将其复制到项目Y的bin目录中;它仅复制X和A程序集。

您有两种选择来解决此问题,这两种选择都将导致程序集B被复制到项目Y的bin目录中:

  1. 在项目Y中添加对程序集B的引用。
  2. 将伪代码添加到使用程序集B的项目X中的文件中。

就个人而言,出于某些原因,我更喜欢选项2。

  1. 如果将来添加另一个引用项目X的项目,则不必记住还包括对程序集B的引用(就像您必须对选项1进行操作一样)。
  2. 您可以有明确的注释,说明为什么需要在其中添加伪代码而不是删除伪代码。因此,如果有人确实删除了代码(例如,使用查找未使用代码的重构工具),则可以从源代码管理中轻松地看到需要该代码并进行还原。如果您使用选项1,并且有人使用重构工具来清理未使用的引用,那么您将没有任何注释;您只会看到从.csproj文件中删除了一个引用。

这是遇到这种情况时通常添加的“虚拟代码”的示例。

    // 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);
    }

4
这里没有讨论的是,在Web项目的/ bin中复制生成产品与将例程复制到目标输出目录(例如/ bin / x86 / Debug)之间存在差异。前者由参考项目在构建时完成,而后者由相关的Web项目完成。检查Microsoft.Common.targets有助于理解这一点。复制到Web / bin根本不依赖于复制本地行为-将复制对复制的本地影响复制到输出目标目录,该目录不是通过Debug运行的Cassini引用的结构的一部分。
user1164178 2014年

6
您能解释一下为什么它与VS一起工作但不添加“虚拟代码”但不能与msbuild一起使用的原因吗?
toebens

3
与调用函数相比,其侵入性更小,您可以将程序集中包含的类的类型分配给虚拟变量。Type dummyType = typeof(AssemblyA.AnyClass);
Arithmomaniac

14
除非您在Visual Studio中选中了“优化代码”设置,否则上面显示的解决方案#2将起作用。在这种情况下,它仍将排除dll。我又添加了一行以覆盖其“优化”。 Console.WriteLine(dummyType.FullName);
JasonG

3
解决方案2在Visual Studio 2017中对我不起作用。我首先认为是因为在我的程序集X中,我只使用了enumfrom B,并且我假定该内联枚举已被内联。我添加了代码以直接使用B中的类型,但没有帮助。我的X总是使用A中的类型来作为B中子类型的情况,因此我无法理解编译器如何认为X不需要B并可以忽略B。这是疯子。
Xharlie

170

我只是这样处理。转到参考的属性,然后执行以下操作:

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

就是这样。

Visual Studio 2010最初并未放置: <private>True</private> 在参考标记中并将“复制本地”设置为false会导致它创建标记。之后,它将相应地将其设置为true和false。


10
这真是天赐之物。这次真是万分感谢!
丽贝卡

22
不适用于MSBuild 4 / VS2012。也就是说,我能够更新引用说,<Private>true</Private>但它似乎对MSBuild没有影响。最后,我只添加了对下级项目的NuGet引用。
Michael Teper

2
没为我工作。它仍然不会将System.Net.Http.Formatting复制到bin文件夹。
2013年

4
这等效于Have you tried turning it off and on again?,并且有效!
guanome

6
看起来VS2015的行为仍然相同:在引用的.dll上将“复制本地”设置为“假”,然后又恢复为“真”。
2015年

38

如果您不是直接在代码中使用程序集,则在尝试提供帮助时Visual Studio会检测到未使用该程序集,并且未在输出中包含该程序集。我不确定为什么您会在Visual Studio和MSBuild之间看到不同的行为。您可以尝试将构建输出都设置为诊断输出,然后比较结果以查看差异之处。

至于您的elmah.dll参考,如果您没有直接在代码中引用它,则可以将其作为项目添加到项目中,并将“构建操作”设置为“ Content复制到输出目录” Always


3
如果未在代码中使用Elmah,则将副本复制到Output Directory注释+1,就可以将其复制为内容。
Kit Roed 2010年

4
实际上,它会忽略不使用的程序集,但要注意的主要事情是,从VS 2010开始,在XAML资源字典中使用程序集不被VS视为使用汇编程序,因此它不会复制它。
2011年


这对于需要dll的单元测试项目更好。我不想添加一个DLL,该DLL不需要主项目就可以使测试运行!
卢克斯

14

看一眼:

我开始的这个MSBuild论坛主题

您将在此处找到我的临时解决方案/解决方法!

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


1
该死的-这也是我唯一的解决方案-希望有更好的方法!
nickspoon

2
请参阅下面的安德鲁(
Andrew

1
对于那些现在正在看这个问题的人来说,Tebens在MSDN上的答案与几年后提供的deadlydog的答案基本相同。
jpaugh

8

我有同样的问题。

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

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


6

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

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

当然,那意味着我在bin中,最重要的是在软件包zip文件中,缺少库的dll文件。我发现这很完美:

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

我不知道为什么要这样做,或者为什么没有这样做。但希望能有所帮助。


在第一步中使用/ t:Build从TeamCity构建整个解决方案,然后在下一个/ t:Package on WebAPI项目上构建整个解决方案时,我遇到了同样的问题。不包括任何项目引用引用的任何dll。使用上面的/ T:Rebuild; WebAPI上的软件包进行了修复,然后包含了这些dll。
安迪·霍伊尔

5

我只是遇到了完全相同的问题,而事实是,同一解决方案中的2个项目引用了第3方库的不同版本这一事实引起了。

一旦我更正了所有参考文献,一切都将完美运行。


4

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

因此,只需在后面的某些代码中重新创建对程序集中的类/组件的虚拟引用,就足以使MSBuild确信该程序实际上已在使用中。


这正是我的问题和有效的解决方案。花了太长时间试图解决这个问题。感谢Scott和@Alex Burstev
卡罗尔

真可悲,这让我发疯。是的,我使用的是FontAwesome.WPF,并且仅从 XAML内部使用(出于明显的原因)。添加虚拟方法有帮助。谢谢!是的,2017年VS 15.6仍然受到影响,所以我申请了一个错误:github.com/dotnet/roslyn/issues/25349
索伦Kuklau

3

将目标框架从.NET Framework 4客户端配置文件更改为.NET Framework 4,为我解决了此问题。

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


3

使用致命狗的计划,

Y => X => A => B

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

通过从Y删除参考X,保存,构建,然后重新添加X参考(项目参考),然后保存,构建,A和B开始显示在Y的bin文件夹中,从而解决了问题。


经过数小时的搜索和尝试许多其他解决方案,该解决方案为我工作。
Suncat2000 '17

2

我遇到了同样的问题,并且dll是动态加载的引用。为了解决该问题,我在dll的名称空间中添加了“使用”。现在,dll被复制到输出文件夹中。




2

出现这种情况的另一种情况是,如果您在Visual Studio中使用的是较旧的“网站”项目类型。对于该项目类型,它无法引用其自身目录结构(当前文件夹和向下文件夹)之外的.dll。因此,在上面的答案中,假设您的目录结构如下所示:

在此处输入图片说明

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


0

今天我有一个类似的问题,这当然不是您所提问题的答案。但我想通知所有人,并可能提供一些见识的火花。

我有一个ASP.NET应用程序。将生成过程设置为清理,然后生成。

我有两个Jenkins CI脚本。一种用于生产,另一种用于舞台。我将我的应用程序部署到暂存阶段,一切正常。部署到生产环境,并且缺少所引用的DLL文件。该DLL文件仅位于项目的根目录中。不在任何NuGet存储库中。DLL设置为do not copy

两个部署之间的CI脚本和应用程序是相同的。仍然在暂存环境中进行清理和部署之后,仍在ASP.NET应用程序的部署位置中替换了DLL文件(bin/)中。生产环境不是这种情况。

事实证明,在一个测试分支中,我向构建过程添加了一个步骤,以将该DLL文件复制到bin目录中。现在该部分花了一些时间才弄清楚。CI流程不会自行清理。该DLL保留在工作目录中,并且意外地与ASP.NET .zip文件打包在一起。生产分支从未以相同的方式复制DLL文件,也从未意外部署它。

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


0

确保两个项目都在相同的.net版本中,并检查复制本地属性,但这应true为默认设置



-1

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

非常沮丧。我解决它的方法是在我的Web项目中包括对该程序包的NuGet引用,即使我没有在那里直接使用它也是如此。


这是最佳答案的重复。
吉尔斯·罗伯茨

-3

在Website项目中从项目引用中包含所有引用的DLL文件并不总是一个好主意,尤其是当您使用依赖项注入时:您的Web项目只想添加对接口DLL文件/项目的引用,而不是任何具体的实现DLL文件。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.