使用 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>
- 无论哪种构建方法生成正确的输出,我都希望 MSBuild 和 VS 生成相同的输出。还是我错了?
- 为什么使用visual studio和nuget/msbuild的包有区别?
- 这是预期的行为还是错误?
显然 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,删除项目的bin
和obj
文件夹,然后在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, when
和if, 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.3
而 netcoreapp3.1
只有 11.0.1
.
我在 msbuild 下使用了下面的 dotnet restore
。但它使用第一个包含 nuget 版本。 net5.0-windows
使用 11.0.1
而 netcoreapp3.1
使用 11.0.1
.
当我在下面使用 VS IDE Restore 时,它使用最后一个 include PackageReference nuget 版本。
net5.0-windows
使用 12.0.3
版本,netcoreapp3.1
使用 11.0.1
版本。
So 我很好奇为什么这种行为在 VS IDE Restore 和 dotnet 之间是不同的恢复命令.
我也在微软论坛上发布了这个问题: 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>
- 无论哪种构建方法生成正确的输出,我都希望 MSBuild 和 VS 生成相同的输出。还是我错了?
- 为什么使用visual studio和nuget/msbuild的包有区别?
- 这是预期的行为还是错误?
显然 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,删除项目的bin
和obj
文件夹,然后在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, when
和if, 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.3
而 netcoreapp3.1
只有 11.0.1
.
我在 msbuild 下使用了下面的 dotnet restore
。但它使用第一个包含 nuget 版本。 net5.0-windows
使用 11.0.1
而 netcoreapp3.1
使用 11.0.1
.
当我在下面使用 VS IDE Restore 时,它使用最后一个 include PackageReference nuget 版本。
net5.0-windows
使用 12.0.3
版本,netcoreapp3.1
使用 11.0.1
版本。
So 我很好奇为什么这种行为在 VS IDE Restore 和 dotnet 之间是不同的恢复命令.