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

在我的Visual Studio解决方案中,我有四个项目(每个项目都针对。net 3.5)——对于我的问题,只有这两个是重要的:

  1. MyBaseProject <-类库引用第三方DLL文件(elma . DLL)
  2. MyWebProject1 <这个web应用程序项目有一个对MyBaseProject的引用

我在Visual studio 2008中通过点击“添加引用…”将elmah.dll引用添加到MyBaseProject中。→“浏览”选项卡→选择“elmah.dll”。

Elmah Reference的属性如下:

  • 别名-全局
  • 本地复制- true
  • 文化- - - - - -
  • 错误日志模块和处理程序(ELMAH)。网
  • 文件类型-程序集
  • 路径- D:\webs\otherfolder\_myPath\__tools\elmah\ elmah .dll
  • 解决-正确
  • 运行时版本- v2.0.50727
  • 指定版本- false
  • 强名称- false
  • 版本- 1.0.11211.0
MyWebProject1中,我通过以下方式添加了对项目MyBaseProject的引用: “添加引用……”→“项目”标签→选择“MyBaseProject”。这个引用的属性除了以下成员外是相同的:

  • 描述- - -
  • 路径- D:\web \CMS\MyBaseProject\bin\Debug\MyBaseProject.dll
  • 版本- 1.0.0.0

如果我在Visual Studio中运行构建,elmah.dll文件将被复制到我的MyWebProject1的垃圾箱目录中,以及MyBaseProject.dll!

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

我已经确保MyBaseProject的.csproj包含值为“true”的私人元素(这应该是Visual Studio中“本地副本”的别名):

<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”为真。我切换“复制本地”为假-保存-并将其设置为真-保存!)

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

我不想在每个项目的postbuild命令中添加一个postbuild复制操作!(假设我有许多项目依赖MyBaseProject!)

170464 次浏览

来看看:

这个MSBuild论坛线程我开始了

你会在那里找到我的临时解决办法!

(MyBaseProject需要一些代码来引用elma .dll中的一些类(无论什么),因为elma .dll被复制到MyWebProject1的bin中!)

如果你没有在代码中直接使用程序集,那么Visual Studio会检测到它没有被使用,并且不会在输出中包含它。我不知道为什么你看到Visual Studio和MSBuild之间有不同的行为。您可以尝试将构建输出设置为诊断输出,并比较结果,看看它在哪里出现分歧。

至于你的elma .dll引用,如果你没有在代码中直接引用它,你可以将它作为一个项目添加到你的项目中,并将构建动作设置为Content,将复制到输出目录设置为Always

我就是这样处理的。转到你引用的属性,这样做:

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

就是这样。

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

我也有同样的问题。

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

在我的例子中,我的客户端是使用“Framework 4客户端”编译的,DLL在“Framework 4”中。

我有同样的问题,dll是一个动态加载的引用。 为了解决这个问题,我在dll的命名空间中添加了一个“using”。

. dll被复制到输出文件夹中

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

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

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

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

我不知道为什么它会起作用,也不知道为什么它一开始就不起作用。但希望这能有所帮助。

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

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

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

所以在你的例子中:设置MyWebProject1上的目标框架为.NET Framework 4

正如Alex Burtsev在评论中提到的,任何只在XAML资源字典中使用的东西,或者在我的例子中,任何只在XAML中使用而不在后面的代码中使用的东西,都不会被MSBuild视为“在使用中”。

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

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

该过程参见我的答案是

引用构建期间未使用的程序集不是正确的实践。您应该扩展构建文件,以便它复制其他文件。可以使用生成后事件,也可以更新属性组。

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

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

因为如果您直接向实现DLL文件/项目添加引用,您不能阻止开发人员在实现DLL文件/项目的具体类上调用“new”,而不是通过接口。你也已经在你的网站上声明了一个“硬代码”来使用这个实现。

我不确定为什么在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试图变得聪明,只把它检测到项目X需要的引用引入项目Y;它这样做是为了避免项目Y中的引用污染。问题是,由于项目X实际上不包含任何显式使用程序集B的代码(例如B.SomeFunction()), VS/MSBuild不会检测到X需要B,因此不会将B复制到项目Y的bin目录中;它只复制X和A程序集。

解决方案

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

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

就我个人而言,出于几个原因,我更喜欢第二种选择。

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

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

一旦我纠正了所有的参考资料,一切都很完美。

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

我有一个ASP。网络应用程序。构建过程被设置为清理然后构建。

我有两个詹金斯 CI脚本。一个用于制作,一个用于分期。我将应用程序部署到登台,一切工作正常。已部署到生产环境,并且缺少一个引用的DLL文件。这个DLL文件只是在项目的根目录中。不在任何NuGet存储库中。DLL被设置为do not copy

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

原来在测试分支中,我已经在构建过程中添加了一个步骤,将这个DLL文件复制到bin目录。现在我花了一点时间才算出来。CI过程本身没有清洁。DLL被留在工作目录中,并被意外地与ASP打包在一起。. NET .zip文件。生产分支从来没有以同样的方式复制DLL文件,也从来没有意外地部署过它。

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

使用致命狗的方案,

Y => x => a => b,

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

我从Y中删除引用X,保存,构建,然后重新添加X引用(一个项目引用),保存,构建,然后a和B开始出现在Y的bin文件夹中。

出现这种情况的另一种情况是,如果您在Visual Studio中使用旧的“Web Site”项目类型。对于该项目类型,它无法引用它自己目录结构(当前文件夹和下)之外的.dll。在上面的答案中,假设你的目录结构是这样的:

enter image description here

如果ProjectX和ProjectY是父/子目录,并且ProjectX引用a .dll,后者又引用B.dll,而B.dll在目录结构之外,例如在根目录(Packages)的Nuget包中,那么a .dll将被包括在内,而B.dll将不包括在内。

确保两个项目都在相同的.net版本中,还要检查copy local属性,但默认值应该是true

使用Visual Studio 2015添加附加参数

/ deployonbuild = false

到msbuild命令行修复了该问题。

我认为@deadlydog的答案在当前的Nuget系统中是无效的。我用Y =>X =比;=比;B在visual studio 2022,我所要做的就是在终端运行命令

msbuild -t:clean,rebuild,pack