使用 MSBuild 时加载的 nuget 包与使用 Visual Studio 构建时加载的不同 nuget 包

Different nuget-packages loaded when using MSBuild than building using Visual Studio

我也在微软论坛上发布了这个问题: https://docs.microsoft.com/en-us/answers/questions/249621/different-nuget-packages-are-used-when-compiling-u.html

考虑以下 .csproj 文件:

 <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
   <PropertyGroup>
     <OutputType>WinExe</OutputType>
     <TargetFrameworks>netcoreapp3.1;net5.0-windows</TargetFrameworks>
     <UseWPF>true</UseWPF>
   </PropertyGroup>
    
     <ItemGroup>
         <PackageReference Include="Newtonsoft.Json" Version="12.0.3" Condition="'$(TargetFramework)' == 'net5.0-windows'"/>
         <PackageReference Include="Newtonsoft.Json" Version="11.0.1" />
     </ItemGroup>
 </Project>

除了创建项目时visual studio生成的文件外,本项目中没有其他文件。生成的文件(.csproj 文件除外)不会以任何方式更改。

如图所示,visual studio 将 - 对于两个项目 - 引用 11.0.1 版本,并使用 11.0.1 版本构建可执行文件。

在命令行中使用 MSBuild 时

<msbuildpath> <projectpath> /restore

将使用 .net5.0 目标的 12.0.3 版本和其他目标的 11.0.1 版本生成可执行文件

当从命令行使用 nuget.exe /restore 时,它​​还会生成资产文件以将 12.0.3 用于 .net5.0,将 11.0.1 用于其他目标。

为什么使用 visual studio 和 nuget/msbuild 的包有区别? 这是预期的行为还是错误?

*作为旁注,使用 choose/when 标签时问题会自行解决

<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
   <PropertyGroup>
     <OutputType>WinExe</OutputType>
     <TargetFrameworks>netcoreapp3.1;net5.0-windows</TargetFrameworks>
     <UseWPF>true</UseWPF>
   </PropertyGroup>
    
     <Choose>
         <When Condition="'$(TargetFramework)' == 'net5.0-windows'">
             <ItemGroup>
                 <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
             </ItemGroup>
         </When>
         <Otherwise>
             <ItemGroup>
                 <PackageReference Include="Newtonsoft.Json" Version="11.0.1" />
             </ItemGroup>
         </Otherwise>
     </Choose>
 </Project>

显然 Visual Studio 没有像 MSBuild 那样处理 MSBuild 脚本中的条件,因此会产生其他结果。我找不到有关他们是否会解决此问题的任何信息。根据这个 post,可能不是因为自 VS2010 以来这已经在进行了。 https://medium.com/@corradocavalli/msbuild-conditions-and-visual-studio-6c5c9347cccf

正如@Kit 在对 OP 的评论中所说,使用 Choose/When 将解决该问题。 无论如何,我会将其标记为已回答,直到出现更好的答案。

请先看更新

VS IDE Restore 和nuget restore,msbuild -t:Restore命令行有很大区别

这不是我在 VS IDE 还原和命令行还原之前遇到的第一个问题。 See this issue which I raised a few days before.

主要问题是VS IDE恢复问题有点多,需要修复。

我已将此问题报告给团队。参见 one and two。如果我没有详细描述问题,您可以关注问题、投票并添加任何评论。

因为这个过程可能需要很长时间,现在,你必须使用我的解决方法,放弃 VS IDE 还原并改为使用还原命令:

1)进入工具-->选项-->Nuget 包管理器 并取消选中这两个选项,以防 vs ide 后端继续使用 ide 恢复来执行错误行为。

2) 右击项目Properties-->Build Event- -> 在 预构建事件命令行 .

下添加 dotnet restore

3)关闭VS,删除项目的binobj文件夹,然后在VS上重启你的项目,点击重建 得到你想要的。

更新 1

我觉得这个问题很奇怪。我认为问题在于:

 <PackageReference Include="Newtonsoft.Json" Version="11.0.1" />

是最后一项,没有条件。它也适用于 net5.0-windows 并且 11.0.1 版本也包括在内,因为它在项目的最后一行。

所以你应该改用这个:

<ItemGroup>
        <PackageReference Include="Newtonsoft.Json" Version="11.0.1" />
        <PackageReference Include="Newtonsoft.Json" Version="12.0.3" Condition="'$(TargetFramework)' == 'net5.0-windows'" />
</ItemGroup>

把条件放在最后

<ItemGroup>
        <PackageReference Include="Newtonsoft.Json" Version="11.0.1" Condition="'$(TargetFramework)' == 'netcoreapp3.1'"/>
        <PackageReference Include="Newtonsoft.Json" Version="12.0.3" Condition="'$(TargetFramework)' == 'net5.0-windows'" />
</ItemGroup>

每一项一个条件(如choose, when),避免targetframework net5.0包含两次nuget包,这样就不会导致复杂的情况.

但是choose, whenif, else一样,只会根据条件执行一个项目,但是你的第一个provided代码不一样,那是两个PackageReference include item,MSBuild会同时执行,执行第二行时,net5.0-windows和[=26=都适用],因此 11.0.1 版本将包含在 net5.0-windows 中。那是正常的。

重要分析

问题是,VSIDE恢复只会显示上次的版本PackageReference 包含项目并使用该版本。

在你的ide中,这些是你使用的:

<ItemGroup>
         <PackageReference Include="Newtonsoft.Json" Version="12.0.3" Condition="'$(TargetFramework)' == 'net5.0-windows'"/>
         <PackageReference Include="Newtonsoft.Json" Version="11.0.1" />
</ItemGroup>

由于 11.0.1 是最后一个包含,所以它总是显示 11.0.1。但是 Restore Command line 不同,它只显示第一个 PackageReference include 节点。在你的 side 中,如果你使用 dotnet Restore Command line,它将使用第一个节点 12.0.3。它忽略了第二行,尽管它确实如此。

这是我的环境:

这种情况下,net5.0-windows有两个include,依次是 11.0.1,12.0.3netcoreapp3.1 只有 11.0.1.

我在 msbuild 下使用了下面的 dotnet restore。但它使用第一个包含 nuget 版本。 net5.0-windows 使用 11.0.1netcoreapp3.1 使用 11.0.1.

当我在下面使用 VS IDE Restore 时,它使用最后一个 include PackageReference nuget 版本。

net5.0-windows 使用 12.0.3 版本,netcoreapp3.1 使用 11.0.1 版本。

So 我很好奇为什么这种行为在 VS IDE Restoredotnet 之间是不同的恢复命令.