问题描述
我们有大约100个项目的大型解决方案,这些项目取决于许多NuGet软件包,其中一些是内部开发的。这个问题是关于作为解决方案中心的主要Web应用程序的。
我们想考虑迁移到新的SDK样式的项目(在可行的情况下),第一步是将所有项目迁移到PackageReference。这是一个大麻烦事-代码建立时
- 在带有
msbuild
的控制台上,我们在bin文件夹中获得System.Buffers
版本4.0.3.0。 - 在带有
devenv /build
的控制台上,我们在bin文件夹中获得System.Buffers
版本4.0.3.0。 - 在VS IDE(我使用16.7.7)中,我们在bin文件夹中获得
System.Buffers
4.0.2.0版( !!! )。
我已经确定差异是由为相关Web应用程序生成的project.assets.json差异引起的。
差异很大,但是绝对的大多数差异是控制台构建的package.assets.json包含的内容比IDE构建的内容多得多。然后是System.Buffers:
注意:
- 没有项目明确引用System.Buffers
- 我们有一个流程来确保所有项目都引用特定NuGet软件包的完全相同版本。不遵守将使PR构建失败。但是,这对这些NuGet包的传递依赖关系没有帮助。因此,我们不得不处理程序集绑定重定向(即使我们所有的项目都是未签名的-没关系,许多依赖项也已签名)
- 内部版本之间未更改任何代码,仅删除了相应Web应用程序的bin文件夹
我的问题-有人遇到过吗? devenv /build
产生与msbuild
完全相同的 project.assets.json 文件的事实使我感到惊讶。
我的理论-与VS所采用的快速最新启发式技术有关。但是我不想禁用它-这可以节省大量时间。只是一个理论,一个薄弱的理论,因为毕竟代码没有改变。
我的方法是运行以下脚本:
$FileItem = Get-Item .\bin\_PublishedWebsites\MyWebApp\bin\System.Buffers.dll
del $FileItem.Directory.FullName -r -Force
r.ps1 -NoPull -Main -NoValidateSolutions
[reflection.assemblyname]::GetAssemblyName($FileItem.FullName)
Copy-Item .\UI\MyWORKBits\obj\project.assets.json c:\temp\_msbuild.project.assets.json
del $FileItem.Directory.FullName -r -Force
devenv Main.sln /build
[reflection.assemblyname]::GetAssemblyName($FileItem.FullName)
Copy-Item .\UI\MyWORKBits\obj\project.assets.json c:\temp\_devenv.project.assets.json
del $FileItem.Directory.FullName -r -Force
$VSInstanceFinder = (Get-ToolFromNuGet VSInstanceFinder 1.0.20009.1).FullName
Add-Type -Path $VSInstanceFinder
$dte = [VSInstanceFinder2.Program]::Find((Get-Item .\Main.sln).FullName)
$dte.Solution.SolutionBuild.Build()
while (!(Test-Path $FileItem.FullName))
{
Write-Host -NoNewline '.'
Start-Sleep 10
}
[reflection.assemblyname]::GetAssemblyName($FileItem.FullName)
Copy-Item .\UI\MyWORKBits\obj\project.assets.json c:\temp\_ide.project.assets.json
bc c:\temp\_console.project.assets.json c:\temp\_devenv.project.assets.json
bc c:\temp\_console.project.assets.json c:\temp\_ide.project.assets.json
最低复制量
我仍在进行最小限度的复制,以全面展示该问题。但是,为了证明project.assets.json是不同的,尽管以一种无辜的方式,这足以说明一个小项目。
Common.csproj
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{04455D86-A7A4-41E5-B3ED-B0BC65EAFDFD}</ProjectGuid>
<OutputType>Library</OutputType>
<AssemblyName>xyz.Common</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<OutputPath>Bin\Debug\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<OutputPath>Bin\Release\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Compile Include="Dummy.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Antlr">
<Version>3.5.0.2</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
dummy.cs
using Antlr;
让我们在VS IDE中进行构建,并检查project.assets.json文件:
C:\work\vsbug [master]> dir .\obj\project.assets.json | sls projectName
obj\project.assets.json:76: "projectName": "Common",C:\work\vsbug [master]>
因此projectName被报告为 Common 。现在,让我们在控制台上构建:
C:\work\vsbug [master]> msbuild /restore .\Common.csproj /v:q
Microsoft (R) Build Engine version 16.7.0+b89cb5fde for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.
C:\work\vsbug [master]> dir .\obj\project.assets.json | sls projectName
obj\project.assets.json:76: "projectName": "xyz.Common",C:\work\vsbug [master]>
这次,项目名称为 xyz.Common 。
就我而言,这是一个良性差异。但这不应该放在首位,并且可能是我们采用大型解决方案时遇到的问题的症状。
请注意,使用SDK样式项目可以消除差异,但是我不能在大型解决方案中使用它。
devenv /safemode
似乎根本没有还原任何NuGet软件包,因此代码无法编译,我无法弄清楚如何使其工作。目前完全没用。
我将尝试使用不同的套件来产生最小的复制品,但是我已经有一个问题-为什么项目名称不同?
编辑1
有一个建议可以从预构建步骤开始运行msbuild.exe -t:restore
。由于我的解决方案有127个C#项目(加上一个实用程序项目),因此修改每个项目都是不合理的。相反,我将以下目标添加到Directory.Build.targets
:
<Project>
<Target Name="MSBuildRestore" BeforeTargets="BeforeBuild" Condition="'$(BuildingInsideVisualStudio)' == True">
<Exec Command=""$(MSBuildBinPath)\msbuild.exe" /t:Restore /v:q /nologo /m $(MSBuildProjectFullPath)" />
</Target>
</Project>
我仍然必须评估此更改对构建的影响。毕竟,此命令递归到该项目所依赖的每个项目。每个项目都将调用它。
幸运的是,似乎没有破坏Visual Studio的“快速更新”启发式技术,因此我将对其进行一些研究,看看它是否没有意外的惊喜。
编辑2
不幸的是,从预构建步骤生成project.assets.json并不是解决方案。显然,此文件用作构建的输入。下面的简单场景显示了该行为:
- 内置msbuild
- 设置
DisableFastUpToDateCheck = true
以禁用“快速更新”启发式 - 打开VS
- 使用二进制日志记录在VS中进行构建(使用Project System Tools生成日志)
检查日志可以发现实际上是在重新编译项目,因为project.assets.json
文件是在每次构建之前重新生成的。
不好。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)