关于 dotnet-build-analysis
帮助 Agent 解读并处理 MSBuild 构建输出的技能,面向 .NET 开发与故障排查。通过错误代码、NuGet 还原问题和分析器警告等示例,提供诊断步骤与修复方向。
主要功能
- 01解析编译器与 MSBuild 错误前缀
- 02诊断 NuGet 还原失败
- 03判断分析器警告的处理方式
- 04排查多目标构建差异
- 05分析本地成功但 CI 失败的问题
适用场景
- 01定位缺失包或版本冲突
- 02判断 C# 编译错误的来源
- 03处理 CI 中的分析器告警
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ wshaddix/ dotnet-skills --skill dotnet-build-analysis安装后在 Claude Code 中输入/dotnet-build-analysis确认已加载。
详细介绍
dotnet-build-analysis
概览 / 范围边界
帮助 Agent 解读并处理 MSBuild 构建输出。涵盖错误代码前缀、NuGet 还原失败、分析器警告解读、多目标框架构建差异,以及“本地可运行,CI 中失败”的诊断模式。每个小节都包含示例输出、诊断步骤和修复模式。
**不在范围内:**编写或修改 .csproj 文件(由 [skill:dotnet-csproj-reading] 负责)。项目结构决策(由 [skill:dotnet-project-structure] 负责)。Agent 常见代码错误(由 [skill:dotnet-agent-gotchas] 负责)。
前置条件
.NET 8.0+ SDK。MSBuild(包含在 .NET SDK 中)。了解 SDK 样式的项目格式。
交叉参考:[skill:dotnet-agent-gotchas],了解导致构建错误的常见代码错误;[skill:dotnet-csproj-reading],了解项目文件结构和修改;[skill:dotnet-project-structure],了解项目组织和 SDK 选择。
错误代码前缀
MSBuild 输出使用标准化前缀来标明错误来源。了解前缀可以判断错误由哪个系统产生,以及应从何处着手修复。
CS —— C# 编译器错误和警告
由 Roslyn C# 编译器产生。这些是源代码中的语言级问题。
示例输出:
src/MyApp.Api/Services/OrderService.cs(42,17): error CS0246: The type or namespace name 'OrderDto' could not be found (are you missing a using directive or an assembly reference?)
src/MyApp.Api/Models/User.cs(15,9): warning CS8618: Non-nullable property 'Name' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
诊断:
- 从错误中解析文件路径和行号——
src/MyApp.Api/Services/OrderService.cs第 42 行,第 17 列。 - CS0246 表示缺少类型。请检查:该类型是否已定义?是否导入了命名空间?项目是否引用了包含该类型的程序集?
- CS8618 是可空引用类型警告。此属性需要
required修饰符、可空注释(string?)或构造函数初始化。
修复模式:
- CS0xxx(语法/类型错误):在指定位置修复源代码。添加
using指令、修正类型名称或添加缺失的引用。 - CS8xxx(可空性警告):添加 null 注释、null 检查或
required修饰符。不要使用#pragma或!运算符来抑制警告。
MSB —— MSBuild 引擎错误
由 MSBuild 构建引擎本身产生。这些错误表示项目文件存在问题、目标执行失败或构建系统配置错误。
示例输出:
error MSB4019: The imported project "C:\Program Files\dotnet\sdk\9.0.100\Microsoft\VisualStudio\v17.0\WebApplications\Microsoft.WebApplication.targets" was not found. Confirm that the expression in the Import declaration "..." is correct.
error MSB3644: The reference assemblies for .NETFramework,Version=v4.8 were not found. You might need to install the developer pack for this framework version.
诊断:
- MSB4019:缺少 MSBuild
.targets文件。通常是 SDK 类型错误、缺少工作负载或 SDK 安装损坏所致。 - MSB3644:目标框架版本的目标包未安装。项目以 .NET Framework 为目标,但只安装了 .NET(Core)SDK 时经常会出现此问题。
修复模式:
- MSB4019:确认
<Project Sdk="...">正确(例如,ASP.NET Core 使用Microsoft.NET.Sdk.Web)。运行dotnet workload list,并安装缺失的工作负载。 - MSB3xxx:检查
<TargetFramework>的值。确保已安装所需的 SDK 或目标包。
NU —— NuGet 错误和警告
由 NuGet 包管理器在还原或打包操作期间产生。
示例输出:
error NU1101: Unable to find package Newtonsoft.Json.Extensions. No packages exist with this id in source(s): nuget.org
warning NU1603: Microsoft.EntityFrameworkCore 9.0.0 depends on Microsoft.Extensions.Caching.Memory (>= 9.0.0) but version Microsoft.Extensions.Caching.Memory 8.0.1 was resolved. Approve the package to suppress this warning.
error NU1605: Detected package downgrade: Microsoft.Extensions.Logging from 9.0.0 to 8.0.1. Reference the package directly from the project to select a different version.
诊断:
- NU1101:包 ID 不存在。检查拼写、确认已配置包源,并检查包是否已重命名或弃用。
- NU1603:传递依赖版本冲突。某个包要求的版本高于最终解析的版本。
- NU1605:检测到显式降级。两个包要求同一依赖项的不同版本。
修复模式:
- NU1101:修正包名称。在 nuget.org 上搜索正确的 ID。
- NU1603/NU1605:为冲突的包添加直接的
<PackageReference>,并指定兼容版本;也可以使用中心化包管理来固定版本。
IDE — IDE/Roslyn 分析器代码风格诊断
由 Roslyn IDE 分析器生成,用于强制执行代码风格。这些通常是警告,而非错误(除非 .editorconfig 提高了严重性)。
示例输出:
src/MyApp.Api/Program.cs(1,1): warning IDE0005: Using directive is unnecessary.
src/MyApp.Api/Models/Order.cs(8,12): warning IDE0044: Make field readonly
src/MyApp.Api/Services/Report.cs(22,5): warning IDE0058: Expression value is never used
诊断:
- IDE0005:未使用的
using指令。可以安全移除。 - IDE0044:字段只在构造函数中赋值,因此可以设为
readonly。 - IDE0058:方法的返回值被丢弃。可以为其赋值,或使用
_ = ...明确丢弃。
修复模式:
- IDE 分析器用于强制执行代码风格。按照建议进行修改即可修复。可在
.editorconfig中配置严重性,将警告提升为错误,以便在 CI 中强制执行。
CA — .NET 代码分析(FxCop/Microsoft.CodeAnalysis.NetAnalyzers)
由 .NET 代码分析 SDK 分析器生成,用于检查 API 设计、性能、可靠性和安全规则。
示例输出:
src/MyApp.Api/Services/CacheService.cs(34,9): warning CA1848: Use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])'. Using LoggerMessage delegates provides better performance.
src/MyApp.Api/Controllers/UserController.cs(12,5): warning CA2007: Consider calling ConfigureAwait on the awaited task
src/MyApp.Api/Crypto/HashService.cs(8,9): warning CA5351: Do Not Use Broken Cryptographic Algorithms (MD5)
诊断:
- CA1848:高性能日志记录。使用
[LoggerMessage]源生成器特性,而不是在日志调用中使用字符串插值。 - CA2007:库代码的
ConfigureAwait(false)指引。不适用于 ASP.NET Core 应用程序代码(没有SynchronizationContext)。 - CA5351:安全关键问题。MD5 不适用于加密用途。请改用 SHA-256 或 SHA-512。
修复模式:
- CA1xxx(设计):按建议应用 API 修改,以提高 API 一致性。
- CA2xxx(可靠性/性能):按建议修复。在 ASP.NET Core 应用程序中,可以通过
.editorconfig禁用 CA2007。 - CA5xxx(安全):务必修复。这些规则标出了真实的安全漏洞。
NuGet 还原失败
NuGet 还原是构建的第一步。如果失败,就不会进行编译。以下是最常见的还原失败模式。
模式:找不到包
示例输出:
Determining projects to restore...
Writing assets file to disk. Path: /src/MyApp.Api/obj/project.assets.json
/src/MyApp.Api/MyApp.Api.csproj : error NU1101: Unable to find package MyCompany.Shared.Models. No packages exist with this id in source(s): nuget.org
Failed to restore /src/MyApp.Api/MyApp.Api.csproj (in 2.14 sec).
诊断:
- 包 ID 是否拼写正确?NuGet ID 不区分大小写,但必须完全匹配。
- 该包是否来自私有源?请检查
nuget.config中的源配置。NuGet 会从项目目录开始,按层级向上搜索源。 - 是否配置了
packageSourceMapping?如果已配置,必须将该包映射到包含它的源。MyCompany.*模式的优先级高于*通配符。
修复模式:
# Check configured sources
dotnet nuget list source
# Check if nuget.config exists (searches upward from project dir)
ls nuget.config ../nuget.config ../../nuget.config 2>/dev/null
<configuration>
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="MyCompany" value="https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json" />
</packageSources>
<packageSourceMapping>
<packageSource key="nuget.org">
<package pattern="*" />
</packageSource>
<packageSource key="MyCompany">
<package pattern="MyCompany.*" />
</packageSource>
</packageSourceMapping>
</configuration>
模式:版本冲突
示例输出:
error NU1107: Version conflict detected for Microsoft.Extensions.DependencyInjection.Abstractions.
MyApp.Api -> Microsoft.EntityFrameworkCore 9.0.0 -> Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.0)
MyApp.Api -> Microsoft.Extensions.Hosting 8.0.1 -> Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.1)
诊断:
- 两条依赖链要求同一包的不同主版本。
- 沿每条依赖链追踪,找出哪个顶级包固定在较旧版本。
- 通常只需升级较旧的顶级包即可修复。
修复模式:
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.0" />
模式:私有源身份验证失败
示例输出:
Retrying 'FindPackagesByIdAsyncCore' for source 'https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json'.
Response status code does not indicate success: 401 (Unauthorized).
error NU1301: Unable to load the service index for source https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json.
诊断:
- 私有源的凭据缺失或已过期。
- 在 CI 中,检查是否已配置凭据提供程序或 PAT。
- 在本地,使用凭据运行
dotnet nuget update source,或使用 Azure Artifacts Credential Provider。
修复模式:
# Install Azure Artifacts Credential Provider (see official docs for platform-specific steps):
# https://github.com/microsoft/artifacts-credprovider#setup
# Windows: iex "& { $(irm https://aka.ms/install-artifacts-credprovider.ps1) }"
# macOS/Linux: sh -c "$(curl -fsSL https://aka.ms/install-artifacts-credprovider.sh)"
# Or add credentials explicitly to a specific source
dotnet nuget update source MyCompany --username az --password $PAT --store-password-in-clear-text
分析器警告解读
分析器警告由 SDK 中捆绑的 Roslyn 分析器或通过 NuGet 添加的分析器生成。了解何时应修复警告、何时应配置严重性至关重要。
示例输出
src/MyApp.Api/Controllers/OrdersController.cs(27,5): warning CA2007: Consider calling ConfigureAwait on the awaited task [/src/MyApp.Api/MyApp.Api.csproj]
src/MyApp.Api/Services/OrderService.cs(15,16): warning CA1062: In externally visible method 'OrderService.Process(string)', validate parameter 'input' is non-null before using it [/src/MyApp.Api/MyApp.Api.csproj]
src/MyApp.Api/Models/UserDto.cs(8,12): warning IDE0032: Use auto-implemented property [/src/MyApp.Api/MyApp.Api.csproj]
诊断:
- 识别前缀:
CA= 代码分析(.NET 分析器),IDE= IDE 代码样式分析器。 - 检查严重性:除非设置了
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>,否则警告不会导致构建失败。 - 确定规则是否适用于你的项目类型(例如,CA2007 与 ASP.NET Core 无关,因为其中没有 SynchronizationContext)。
- 决定如何处理:修复代码、在
.editorconfig中配置严重性,或提供有据可查的理由后抑制规则。
修复模式:
- 修复代码:当分析器指出实际问题时(CA1062 — 添加 null 验证,或使用
ArgumentNullException.ThrowIfNull)。 - 配置严重性:当规则不适用于整个项目时,在
.editorconfig中配置(见下文)。 - 内联抑制:仅在提供有据可查的理由时使用(见下文的“何时可以接受抑制”)。
严重性级别
| 严重性 | 对构建的影响 | 操作 |
|---|---|---|
| 错误 | 构建失败 | 必须修复后构建才能成功 |
| 警告 | 构建成功(除非设置了 <TreatWarningsAsErrors>true</TreatWarningsAsErrors>) | 修复或在 .editorconfig 中配置 |
| 建议 | 构建成功;在 IDE 中显示 | 条件允许时修复 |
| 隐藏 | 不显示;可通过代码修复获取 | 除非正在主动重构,否则忽略 |
配置严重性
使用 .editorconfig 控制整个项目的分析器行为:
# .editorconfig (place at solution root)
[*.cs]
# Promote nullable warnings to errors (recommended)
dotnet_diagnostic.CS8600.severity = error
dotnet_diagnostic.CS8602.severity = error
dotnet_diagnostic.CS8603.severity = error
# Suppress ConfigureAwait warning in ASP.NET Core apps (no SynchronizationContext)
dotnet_diagnostic.CA2007.severity = none
# Promote security warnings to errors
dotnet_diagnostic.CA5350.severity = error
dotnet_diagnostic.CA5351.severity = error
何时可以接受抑制
仅当符合以下条件时,才可以接受抑制:
- 分析器无法理解代码的安全保证(例如,确保非 null 的自定义保护子句)。
- 该规则不适用于项目类型(例如,ASP.NET Core 应用中的 CA2007)。
- 提供有据可查的理由。
// ACCEPTABLE: documented justification
[SuppressMessage("Reliability", "CA2007:ConfigureAwait",
Justification = "ASP.NET Core has no SynchronizationContext")]
public async Task<Order> GetOrderAsync(int id, CancellationToken ct)
{
return await _repo.GetByIdAsync(id, ct);
}
// NOT ACCEPTABLE: no justification, hides a real issue
#pragma warning disable CA1062
public void Process(string input) { } // input could be null
#pragma warning restore CA1062
多目标构建输出
当项目以多个框架为目标时,MSBuild 会分别构建每个 TFM。错误可能只出现在其中一个目标上。
示例输出
MyApp.Shared -> /src/MyApp.Shared/bin/Debug/net8.0/MyApp.Shared.dll
src/MyApp.Shared/Services/FeatureService.cs(18,30): error CS1061: 'FrozenDictionary<string, int>' does not contain a definition for 'GetAlternateLookup' [/src/MyApp.Shared/MyApp.Shared.csproj -> net8.0]
MyApp.Shared -> /src/MyApp.Shared/bin/Debug/net9.0/MyApp.Shared.dll
Build succeeded for net9.0.
Build FAILED for net8.0.
诊断:
- 错误标记
[...csproj -> net8.0]显示哪个 TFM 构建失败。net9.0构建成功。 GetAlternateLookup是在 .NET 9 中添加的。代码使用了 .NET 8 不支持的 API。- 修复需要使用条件编译,或为较旧的 TFM 使用替代 API。
修复模式:
// Use preprocessor directives for TFM-specific code
#if NET9_0_OR_GREATER
var lookup = frozenDict.GetAlternateLookup<ReadOnlySpan<char>>();
return lookup.TryGetValue(key, out var value) ? value : default;
#else
return frozenDict.TryGetValue(key.ToString(), out var value) ? value : default;
#endif
<PropertyGroup>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="System.Collections.Immutable" Version="8.0.0" />
</ItemGroup>
阅读多目标输出
识别特定 TFM 问题的关键模式:
- 每条诊断行末尾的
[ProjectPath -> TFM]后缀会指出目标框架。 - 结尾处会有
Build succeeded for netX.0/Build FAILED for netX.0摘要。 - 还原输出会显示所有 TFM:
Restored ... (net8.0, net9.0)。 - 构建输出路径包含 TFM:
bin/Debug/net8.0/与bin/Debug/net9.0/。
CI 偏差:本地正常,CI 失败
最令人沮丧的构建失败,是本地通过但在 CI 中失败的情况。这几乎总是由环境差异导致的。
模式:SDK 版本不同
示例场景:
Local: dotnet --version -> 9.0.200
CI: dotnet --version -> 9.0.100
Build error in CI:
error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*.
诊断:
- 本地 SDK(9.0.200)包含 CI SDK(9.0.100)不支持的语言预览功能。
- 缺少
global.json文件,或该文件未固定 SDK 版本。
修复模式:
// global.json -- pin SDK version for consistent builds
{
"sdk": {
"version": "9.0.200",
"rollForward": "latestPatch"
}
}
模式:CI 中缺少工作负载
示例场景:
CI error:
error NETSDK1147: To build this project, the following workloads must be installed: maui-android
诊断:
- 本地已安装 MAUI/Aspire/WASM 工作负载,但 CI 映像中没有。
- CI 管道需要显式添加工作负载安装步骤。
修复模式:
# GitHub Actions example
- name: Install .NET workloads
run: dotnet workload install maui-android maui-ios
模式:隐式 NuGet 源
示例场景:
Local restore succeeds (using cached packages).
CI error:
error NU1101: Unable to find package MyCompany.Internal.Lib.
诊断:
- 本地计算机此前还原时,已将该包放入全局 NuGet 缓存。
- CI 从空缓存开始,且找不到该包,因为未配置私有源。
- 仓库中缺少
nuget.config文件,或 CI 缺少源的凭据。
修复模式:
- 在仓库根目录添加
nuget.config,列出所有必需的包源。 - 配置 CI 以通过凭据提供程序、PAT 或托管标识向私有源进行身份验证。
- CI 构建绝不能依赖全局 NuGet 缓存。
模式:特定操作系统的路径差异
示例场景:
Local (Windows): Build succeeds
CI (Linux): error MSB4018: The "ResolveAssemblyReference" task failed.
Could not find file '/src/MyApp/../Shared/MyLib.dll'
诊断:
- Windows 文件系统不区分大小写;Linux 区分大小写。
- 文件引用的大小写与磁盘上实际文件的大小写不同。
- 或者,MSBuild 属性中使用了 Linux 无法解析的反斜杠路径分隔符。
修复模式:
- 确保文件和目录名称的大小写与项目引用中使用的完全一致。
- 在
.csproj路径中使用正斜杠(/)——MSBuild 会在所有平台上对其进行规范化。 - 推送前,使用
docker run在本地 Linux 容器中测试。
模式:仅在 CI 中将警告视为错误
示例场景:
Local: Build succeeds with 3 warnings
CI: error CS8602: Dereference of a possibly null reference.
(because CI sets TreatWarningsAsErrors=true)
诊断:
- CI 流水线或
Directory.Build.props通过仅适用于 CI 的条件启用了<TreatWarningsAsErrors>true</TreatWarningsAsErrors>。 - 开发者在本地会看到警告,但因为构建成功而从不修复这些警告。
修复模式:
- 在
Directory.Build.props中无条件启用<TreatWarningsAsErrors>true</TreatWarningsAsErrors>,使本地构建和 CI 构建的行为保持一致。 - 修复所有警告。不要添加仅适用于 CI、导致行为与本地不一致的 MSBuild 属性。
Slopwatch 反模式
这些模式表明 Agent 在掩盖构建问题,而不是修复问题。在代码审查期间标记这些模式。请参阅 [skill:dotnet-slopwatch],了解用于检测这些模式的自动化质量门禁。
禁用警告
<PropertyGroup>
<NoWarn>CS8600;CS8602;CS8603;CS8604;IL2026;IL2046</NoWarn>
</PropertyGroup>
// RED FLAG: pragma disable without justification
#pragma warning disable CS8618
public class UserModel
{
public string Name { get; set; } // non-nullable not initialized
public string Email { get; set; }
}
#pragma warning restore CS8618
**修复:**移除 <NoWarn> 条目并修复根本问题。如果确实需要禁用警告,请使用 .editorconfig 设置每条规则的严重性,并添加说明原因的注释。
禁用分析器但未提供理由
// RED FLAG: suppressing security analyzer with no explanation
[SuppressMessage("Security", "CA5351")]
public byte[] HashData(byte[] input)
{
using var md5 = MD5.Create(); // insecure algorithm
return md5.ComputeHash(input);
}
# RED FLAG: disabling entire analyzer categories in .editorconfig
[*.cs]
dotnet_diagnostic.CA5350.severity = none
dotnet_diagnostic.CA5351.severity = none
dotnet_diagnostic.CA5358.severity = none
**修复:**替换不安全算法(MD5 -> SHA-256)。如果无法避免禁用分析器(例如,与要求使用 MD5 的系统互操作),请添加 Justification 字符串说明这一限制。
交叉引用
- [skill:dotnet-agent-gotchas] -- 会导致构建错误的常见 Agent 编码错误
- [skill:dotnet-csproj-reading] -- 项目文件结构、PropertyGroup/ItemGroup 惯例
- [skill:dotnet-project-structure] -- SDK 选择、项目组织、多项目解决方案