MSBuild正在用旧版本替换Newtonsoft.Json.dll

Eir*_*ske 12 c# msbuild teamcity json.net asp.net-web-api

我正在使用TeamCity中的MSBuild运行器来构建ASP.net web api并运行单元测试.一切正常,直到我升级到"Microsoft Build Tools 2017 15.7.2".

突然,msbuild从"C:\ Program Files(x86)\ ISS\Microsoft Web Deploy V3"或"C:\ Program Files\ISS\Microsoft Web"复制旧版本的Newtonsoft.Json.dll(版本6.0.4.17603)在构建解决方案时将V3"部署到输出文件夹.所有项目都使用NuGet引用9.0.1版本.

在构建运行时监视输出文件夹,我可以看到.dll在6.0.4和9.0.1之间来回切换,直到构建结束,并且6.0.4版本仍然存在.

我发现了这个问题,当我将Web部署文件夹中的Newtonsoft.Json.dll文件重命名为Newtonsoft.Json_old.dll时,msbuild没有替换我的9.0.1版本,一切正常.

我已经检查过引用Newtonsoft.Json的所有项目都引用了9.0.1版本并在.csproj文件中使用了正确的Hint-Path.

有谁知道如何解决这个问题?我的解决方案似乎更像是一种解决方法,我想知道为什么msbuild首先复制这个文件.

Sco*_*win 5

摘要

当MSBuild解析程序集时,它会根据您所安装的内容在一些非常奇怪的目录中进行搜索,包括该Web Deploy文件夹。基于MSBuild参考,我认为这是遗留行为。您可以使用项目文件中定义的MSBuild属性来阻止该操作。

在受影响的项目文件中,找到以下行:

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
Run Code Online (Sandbox Code Playgroud)

并将其添加到它下面:

<PropertyGroup>
    <AssemblySearchPaths>$(AssemblySearchPaths.Replace('{AssemblyFolders}', '').Split(';'))</AssemblySearchPaths>
</PropertyGroup>
Run Code Online (Sandbox Code Playgroud)

这将导致MSBuild在解析程序集时不再在有问题的文件夹中查找。


全文

当我们移至Visual Studio 2019时,我的团队遇到了类似的问题。我们的某些项目仍以.NET Framework 4.0为目标,并且在我们的构建代理上安装Visual Studio 2019之后,我们开始在引用了某些项目的项目中遇到一个神秘的错误。我们的核心库:

无法解析主要参考“ OurCoreLibrary,版本= 3.4.2.0,文化=中性,PublicKeyToken = xxxxxxxxxxxxxxxx,processorArchitecture = MSIL”,因为它间接依赖程序集“ Newtonsoft.Json,版本= 9.0.0.0,Culture =中性的,PublicKeyToken = 30ad4fe6b2a6aeed”,它是针对“ .NETFramework,Version = v4.5”框架构建的。此版本比当前目标框架“ .NETFramework,Version = v4.0”更高。

在将项目切换到目标4.5时问题就消失了,但是由于我不会进入这里的原因,我们无法为每个受影响的项目都这样做,所以我决定更深入地研究。

事实证明,您的问题为您提供了一些有关正在发生的事情的见解。我们所引用的Newtonsoft.Json版本与“ C:\ Program Files(x86)\ ISS \ Microsoft Web Deploy V3”中的版本匹配,当我删除该文件时,构建成功。

我们的特定问题是Web Deploy文件夹中的Newtonsoft.Json副本是相同版本(9.0.0.0),但框架错误(4.5而不是4.0),并且由于某种原因,解析逻辑不会检查目标框架,在构建时导致不匹配。更新到VS2019涉及更新Web Deploy,这也将Newtonsoft.Json的副本更新到9.0.0.0,从而导致我们的冲突。

要了解为什么甚至要从头开始查看该程序集,我将MSBuild项目的生成输出详细程度设置为Diagnostic,并查看发生了什么。搜索有问题的路径表明,在ResolveAssemblyReferences任务中,MSBuild正在通过一些意外的地方来查找匹配项:

1>          For SearchPath "{AssemblyFolders}". (TaskId:9)
1>          Considered "C:\Program Files (x86)\Microsoft.NET\ADOMD.NET\140\OurCoreLibrary.winmd", but it didn't exist. (TaskId:9)
1>          Considered "C:\Program Files (x86)\Microsoft.NET\ADOMD.NET\140\OurCoreLibrary.dll", but it didn't exist. (TaskId:9)
1>          Considered "C:\Program Files (x86)\Microsoft.NET\ADOMD.NET\140\OurCoreLibrary.exe", but it didn't exist. (TaskId:9)
1>          Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.0\OurCoreLibrary.winmd", but it didn't exist. (TaskId:9)
1>          Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.0\OurCoreLibrary.dll", but it didn't exist. (TaskId:9)
1>          Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.0\OurCoreLibrary.exe", but it didn't exist. (TaskId:9)
1>          Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.5\OurCoreLibrary.winmd", but it didn't exist. (TaskId:9)
1>          Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.5\OurCoreLibrary.dll", but it didn't exist. (TaskId:9)
1>          Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.5\OurCoreLibrary.exe", but it didn't exist. (TaskId:9)
1>          Considered "C:\Program Files\IIS\Microsoft Web Deploy V3\OurCoreLibrary.winmd", but it didn't exist. (TaskId:9)
1>          Considered "C:\Program Files\IIS\Microsoft Web Deploy V3\OurCoreLibrary.dll", but it didn't exist. (TaskId:9)
1>          Considered "C:\Program Files\IIS\Microsoft Web Deploy V3\OurCoreLibrary.exe", but it didn't exist. (TaskId:9)
1>          Considered "C:\Program Files (x86)\Microsoft SQL Server\140\SDK\Assemblies\OurCoreLibrary.winmd", but it didn't exist. (TaskId:9)
1>          Considered "C:\Program Files (x86)\Microsoft SQL Server\140\SDK\Assemblies\OurCoreLibrary.dll", but it didn't exist. (TaskId:9)
1>          Considered "C:\Program Files (x86)\Microsoft SQL Server\140\SDK\Assemblies\OurCoreLibrary.exe", but it didn't exist. (TaskId:9)
Run Code Online (Sandbox Code Playgroud)

进一步的挖掘显示,搜索到的路径以传递,该路径AssemblySearchPathsMicrosoft.Common.CurrentVersion.targets中定义:

<AssemblySearchPaths Condition=" '$(AssemblySearchPaths)' == ''">
  {CandidateAssemblyFiles};
  $(ReferencePath);
  {HintPathFromItem};
  {TargetFrameworkDirectory};
  $(AssemblyFoldersConfigFileSearchPath)
  {Registry:$(FrameworkRegistryBase),$(TargetFrameworkVersion),$(AssemblyFoldersSuffix)$(AssemblyFoldersExConditions)};
  {AssemblyFolders};
  {GAC};
  {RawFileName};
  $(OutDir)
</AssemblySearchPaths>
Run Code Online (Sandbox Code Playgroud)

根据MSBuild任务参考中的ResolveAssemblyReferences任务SearchPaths参数定义为:

指定搜索目录或特殊位置以查找磁盘上代表程序集的文件。搜索路径的列出顺序很重要。对于每个程序集,从左到右搜索路径列表。找到代表程序集的文件后,该搜索将停止,并开始搜索下一个程序集。

...并定义了一些特殊的常量,包括我们的朋友{AssemblyFolders}

  • {AssemblyFolders}:指定任务将使用Visual Studio.NET 2003从注册表中查找组件。

因为目录是按顺序检查的,所以您可能希望{HintPathFromItem}优先,并且在大多数情况下会这样。但是,如果您依赖于Newtonsoft.Json的较旧版本,则该版本将没有HintPath ,因此它将继续解决。

稍后在Microsoft.Common.CurrentVersion.targets中,我们可以看到在某些情况下显式删除了此常数,这就是上面的答案来自于:

<PropertyGroup Condition="'$(_TargetFrameworkDirectories)' == '' and '$(AssemblySearchPaths)' != '' and '$(RemoveAssemblyFoldersIfNoTargetFramework)' == 'true'">
  <AssemblySearchPaths>$(AssemblySearchPaths.Replace('{AssemblyFolders}', '').Split(';'))</AssemblySearchPaths>
</PropertyGroup>
Run Code Online (Sandbox Code Playgroud)

删除此常量会从考虑中删除有问题的文件夹,并且老实说,我无法想到一种情况,即我希望程序集隐式解析为在Web Deploy或SQL Server SDK中闲逛的任何版本,例如Newtonsoft.Json。夹。话虽这么说,我敢肯定有一个案例,将其关闭会导致某些问题,因此请记住这一点。

  • 虽然我已经有一段时间没有遇到这个问题了,我不记得我是如何解决它的,但这个答案解释了很多这是如何发生的,并且非常有用。感谢您抽出宝贵时间提供如此详细的答案! (2认同)