.net 为什么控制台构建生成的project.assets.json与使用VS IDE构建生成的project.assets.json完全不同?

.net 为什么控制台构建生成的project.assets.json与使用VS IDE构建生成的project.assets.json完全不同?,.net,visual-studio,msbuild,nuget,devenv,.net,Visual Studio,Msbuild,Nuget,Devenv,我们有大约100个项目的大解决方案,这些项目依赖于许多NuGet软件包,其中一些是内部开发的。这个问题是关于主web应用程序的,它是这个解决方案的中心 我们想考虑迁移到新的SDK风格的项目(我们可以),第一步是将所有的项目迁移到打包访问。当代码构建时,出现了一个大麻烦 在带有msbuild的控制台上,我们在bin文件夹中获得System.Buffersversion 4.0.3.0 在带有devenv/build的控制台上,我们在bin文件夹中获得System.Buffersversion 4

我们有大约100个项目的大解决方案,这些项目依赖于许多NuGet软件包,其中一些是内部开发的。这个问题是关于主web应用程序的,它是这个解决方案的中心

我们想考虑迁移到新的SDK风格的项目(我们可以),第一步是将所有的项目迁移到打包访问。当代码构建时,出现了一个大麻烦

  • 在带有
    msbuild
    的控制台上,我们在bin文件夹中获得
    System.Buffers
    version 4.0.3.0
  • 在带有
    devenv/build
    的控制台上,我们在bin文件夹中获得
    System.Buffers
    version 4.0.3.0
  • 在VSIDE(我使用16.7.7)中,我们在bin文件夹中获得
    System.Buffers
    version 4.0.2.0(!!!
我已经确定,差异是由为相关web应用程序生成的project.assets.json中的差异造成的

差异是巨大的,但绝大多数差异是控制台构建的package.assets.json包含的内容比IDE构建的内容多得多。然后是系统。缓冲区:

注:

  • 没有项目显式引用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>
让我们在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]>
因此,项目名称报告为通用。现在让我们在控制台上构建:

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#项目(加上一个公用事业项目),因此修改每个项目是不合理的。相反,我将以下目标添加到
目录.Build.targets

<Project>
  <Target Name="MSBuildRestore" BeforeTargets="BeforeBuild" Condition="'$(BuildingInsideVisualStudio)' == True">
    <Exec Command="&quot;$(MSBuildBinPath)\msbuild.exe&quot; /t:Restore /v:q /nologo /m $(MSBuildProjectFullPath)" />
  </Target>
</Project>

我仍然需要评估此更改对构建的影响。毕竟,这个命令会递归到它所依赖的每个项目。每一个项目都会称之为

幸运的是,它似乎没有打破VisualStudio的快速更新启发,所以我将使用它运行一段时间,看看它是否没有意外的惊喜

编辑2

不幸的是,从预构建步骤生成project.assets.json并不是一个解决方案。显然,此文件用作构建的输入。以下简单场景显示了该行为:

  • 内置msbuild
  • 设置
    disablefastupdatecheck=true
    以禁用快速更新启发式
  • 开放VS
  • 带二进制日志记录的内置VS(使用项目系统工具生成日志)
  • 检查日志可以发现项目实际上是重新编译的,因为
    project.assets.json
    文件是在每次构建之前重新生成的


    不好。

    研究

    这似乎是VS IDE restoremsbuild restore之间的一个问题,我在许多项目和PC中也遇到了这个问题。因此,到目前为止,这是一个相当大的问题,感谢您指出这个问题

    ================================

    VS IDE还原上的
    projects.assert.json

    ================================

    msbuild还原时的
    projects.assert.json

    我已经报告了,如果我没有详细描述该问题,您可以对其进行投票并添加任何评论,这样它将得到微软更多的关注。我希望团队能给你一个满意的答复

    建议

    由于该过程可能需要一段时间,作为消除差异的建议,您可以尝试以下功能:

    您只需在VS IDE中的项目预构建事件上添加命令行即可:

    msbuild $(MSBuildProjectFullPath) -t:restore
    
    1)右键单击项目属性-->生成事件msbuild $(MSBuildProjectFullPath) -t:restore