Azure Pipelines Nuget 还原失败 MSB4226

Posted

技术标签:

【中文标题】Azure Pipelines Nuget 还原失败 MSB4226【英文标题】:Azure Pipelines Nuget Restore Failing MSB4226 【发布时间】:2022-01-18 00:43:20 【问题描述】:

我正在尝试为项目设置 Azure 管道,但我的 yml 中的 nuget restore 命令失败。以下是完整的错误:

[错误] nuget 命令失败,退出代码(1) 和错误(D:\a\1\s\UDesign\Backup\UDesign\UDesign.csproj(190,11): 错误 MSB4226: 导入的项目"找不到 C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets。另外,试图找到“Microsoft\VisualStudio\v10 .0\WebApplications\Microsoft.WebApplication.targets" 在 $(MSBuildExtensionsPath32) 的后备搜索路径中 - "C:\Program Files (x86)\MSBuild" 。这些搜索路径在 "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe.Config"。确认声明中的路径是正确的,并且该文件存在于磁盘上的任一搜索路径中。) ##[error]包恢复失败

几乎所有关于此错误的帖子都在 YML 中的 Build 命令上,但在 Nuget Restore 上却失败了:

Pipelines failure image

YML 下面:

# .NET Desktop
# Build and run tests for .NET Desktop or Windows classic desktop solutions.
# Add steps that publish symbols, save build artifacts, and more:
# https://docs.microsoft.com/azure/devops/pipelines/apps/windows/dot-net

trigger:
- master

pool:
  vmImage: 'windows-latest'

variables:
  solution: '**/*.sln'
  buildPlatform: 'Any CPU'
  buildConfiguration: 'Release'

steps:
- task: NuGetToolInstaller@1

- task: NuGetCommand@2
  inputs:
    command: 'restore'
    restoreSolution: '$(solution)'
    feedsToUse: 'select'
    vstsFeed: 'MyFeed'

- task: VSBuild@1
  inputs:
    solution: '$(solution)'
    msbuildArgs: '/p:OutputPath="$(Build.BinariesDirectory)\$(Build.BuildID)"'
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'
    restoreNugetPackages: true
    msbuildArchitecture: 'x64'

- task: ArchiveFiles@2
  inputs:
    rootFolderOrFile: '$(Build.BinariesDirectory)\$(Build.BuildId)'
    includeRootFolder: false
    archiveType: 'zip'
    archiveFile: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip'
    replaceExistingArchive: true

- task: PublishBuildArtifacts@1
  inputs:
    PathtoPublish: '$(Build.ArtifactStagingDirectory)'
    ArtifactName: 'drop'
    publishLocation: 'Container'

我不确定问题出在配置上还是我的 NuGet 包上,我在这个问题上找不到太多信息。

【问题讨论】:

UDesign.csproj 是解决方案的一部分吗? 不,它不是它的一部分 解决方案的根目录中有nuget.config 吗? 不,我正在使用工件提要,并且根据日志,它看起来可以正确找到包。 【参考方案1】:

实际问题

这个问题实际上与 NuGet 无关,只是 NuGet 是管道中尝试评估 MSBuild 文件的第一件事。如果你仔细看错误:

错误 MSB4226:找不到导入的项目“C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets”。

可以看到报错是MSBuild找不到Microsoft.WebApplication.targets。这是什么意思?我不是 100% 有信心,但我非常有信心,这意味着您使用的是“自托管”CI 代理,而不是 a Microsoft hosted agent,并且任何设置机器的人都安装了 Visual Studio 2019 而没有安装 ASP.NET工作量。因此,任何设置 CI 代理的人都应该安装“ASP.NET 和 Web 开发”工作负载。

建议 1:CI 代理应使用 BuildTools SKU

如果您查看VS's release and build history,您会看到每个版本的“安装程序链接”下都有一个“BuildTools”链接。这是 Visual Studio 的一个子集,没有所有的 GUI 东西,专门用于 CI 代理。我认为 BuildTools SKU 没有工作负载选项,它只是安装所有工作负载所需的所有构建工具。

只有在极少数情况下,CI 代理才需要“完整”的 Visual Studio,因此除非您知道自己处于这种情况,否则我建议您在 CI 代理上安装 BuildTools,而不是在 Enterprise 或 Professional 上安装。

建议2:不要使用NuGetCommand

有两个原因。首先,NuGetCommand 是一个使用 NuGet.exe 的任务。 NuGet.exe 的问题在于,当您使用PackageReference 而不是packages.config 时,有时NuGet 和构建工具(msbuild 的道具/目标)会更改临时文件的文件格式。如果您没有使 NuGet.exe 的版本与 MSBuild/Visual Studio 的版本保持一致,则可能会出现构建错误。所以,最好使用dotnet restore,或者如果你不能使用dotnet cli,那么使用msbuild -t:restore。这样,您始终可以使用专为安装的 dotnet/msbuild 版本设计的 NuGet 的确切版本,并且您再也不必考虑 NuGet-MSBuild 版本问题。

其次,someone from the Azure DevOps team told my team that they want to deprecate these "heavy" tasks, and suggest customers call commands directly in a script task。特别是,他们实现这些功能的方式将破坏 NuGet 的新包源映射功能。

如果你的解决方案只包含 SDK 风格的项目,那么我建议你使用:

- task: NuGetAuthenticate
  displayName: Set up NuGet authentication
- script: dotnet restore $(solution)
  displayName: Restore

如果您的解决方案包含任何“遗留”(非 SDK 样式)项目,则不要使用 dotnet CLI,而是使用 - script: msbuild -t:restore $(solution)

建议 3:不要使用 VSBuild

您正在使用任务VSBuild 来运行您的构建。这是一个使用devenv.com 构建项目的任务。虽然 devenv 确实具有从命令行构建的命令行参数,但 msbuild.exe 是进行命令行构建的“官方”工具。同样,除非您知道自己处于真正需要通过devenv /build 构建的特殊情况,否则我建议您改用dotnet CLI 或MSBuild。如前所述,Azure DevOps 团队显然希望弃用“繁重”任务,因此我建议您使用脚本并直接调用dotnetmsbuild

- script: msbuild -t:build $(solution)
  displayName: Build solution

【讨论】:

这是 Azure 中有效的 Yml?这似乎不符合可以为我的管道设置的任务。例如,根据构建器的说法,您链接的任务似乎都不是有效的 yml? Fwiw 切换到 DotNetCoreCLI 并运行恢复似乎有所帮助,但这对我来说没有多大意义,因为我们没有使用核心。此外,它在 MSBuild 上失败并且无法从还原中找到任何 nuget 包,所以我不确定这是正确的解决方案。 恢复:-任务:DotNetCoreCLI@2 输入:命令:'恢复'项目:'*/.sln' feedsToUse:'select' vstsFeed:'Feed' noCache:真正的 MSBuild:-任务:MSBuild@1 输入:解决方案:'**/MyProject.sln' 作为后续,我们正在使用已发布的 yaml 中指定的 windows 托管代理:windows-latest,not self hosting 这是一个 sn-p 而不是一个完整的 yaml 文件,但是是的,它是有效的。 Here's the docs for the script keyword,假设您认为这是无效的。否则我不确定你认为什么是无效的。 如果任何项目使用packages.config,那么as per nuget's docs, you need to use msbuild -t:restore -p:RestorePackagesConfig=true。否则,我没有足够的信息来帮助理解为什么构建会因缺少包而失败。这是我个人不喜欢 Azure DevOps 的 NuGetCommand 和 MSBuild 任务的原因之一,因为像传递你想要的参数这样简单的事情更难。我更喜欢自己运行命令行。【参考方案2】:

你可以试试这个

注意:你需要根据你的项目替换源路径和目标路径。

variables:
- name: BuildParameters.RestoreBuildProjects
  value: '**/*.csproj'
- name: BuildParameters.TestProjects
  value: '**/*[Tt]ests/*.csproj'
trigger:
  branches:
    include:
    - refs/heads/master
name: $(date:yyyyMMdd)$(rev:.r)
jobs:
- job: Job_1
  displayName: Agent job 1
  pool:
    vmImage: windows-2019
  steps:
  - checkout: self
  - task: DotNetCoreCLI@2
    displayName: Restore
    inputs:
      command: restore
      projects: $(BuildParameters.RestoreBuildProjects)
  - task: DotNetCoreCLI@2
    displayName: Build
    inputs:
      projects: $(BuildParameters.RestoreBuildProjects)
      arguments: --configuration $(BuildConfiguration)
  - task: DotNetCoreCLI@2
    displayName: Test
    enabled: False
    inputs:
      command: test
      projects: $(BuildParameters.TestProjects)
      arguments: --configuration $(BuildConfiguration)
  - task: DotNetCoreCLI@2
    displayName: Publish
    inputs:
      command: publish
      publishWebProjects: True
      projects: $(BuildParameters.RestoreBuildProjects)
      arguments: --configuration $(BuildConfiguration) --output $(build.artifactstagingdirectory)
      zipAfterPublish: True
  - task: PublishBuildArtifacts@1
    displayName: Publish Artifact
    condition: succeededOrFailed()
    inputs:
      PathtoPublish: $(build.artifactstagingdirectory)
      TargetPath: '\\my\share\$(Build.DefinitionName)\$(Build.BuildNumber)'
...

【讨论】:

从事 Azure DevOps 工作的人似乎是 suggesting to not use task: DotnetCoreCLI, and instead to just use a script task and run the dotnet CLI directly。 无论哪种方式,它也会失败,但出现错误:' Build FAILED。 “D:\a\1\s\Configurator\Configurator.csproj”(恢复目标)(1) -> D:\a\1\s\Configurator\Configurator.csproj(1,1):错误MSB4075:项目文件“D:\a\1\s\Configurator\Configurator.csproj”必须在 Visual Studio IDE 中打开并转换为最新版本,然后才能由 MSBuild 构建。 0 警告 1 错误 已用时间 00:00:00.07 ##[error]Error: The process 'C:\Program Files\dotnet\dotnet.exe' failed with exit code 1 ##[error]Packages无法恢复'

以上是关于Azure Pipelines Nuget 还原失败 MSB4226的主要内容,如果未能解决你的问题,请参考以下文章

Azure 构建管道 NuGet 还原错误 NETSDK1045

Azure Devops 私有构建代理在 nuget 还原任务中失败

使用 docker 将代码覆盖率结果添加到 Azure Pipelines for .NET6 Web API

我可以通过 CLI 验证 azure-pipelines.yml 文件吗?

建立Azure Dev Ops持续集成和持续交付(CICD)(使用 Azure Pipelines 建立CICD)

建立Azure Dev Ops持续集成和持续交付(CICD)(使用 Azure Pipelines 建立CICD)