mcpField
D
dotnet-build-analysis

dotnet-build-analysis

github.com/wshaddix开发8677 次安装35 周前更新
代码仓库

关于 dotnet-build-analysis

帮助 Agent 解读并处理 MSBuild 构建输出的技能,面向 .NET 开发与故障排查。通过错误代码、NuGet 还原问题和分析器警告等示例,提供诊断步骤与修复方向。

主要功能

  1. 01解析编译器与 MSBuild 错误前缀
  2. 02诊断 NuGet 还原失败
  3. 03判断分析器警告的处理方式
  4. 04排查多目标构建差异
  5. 05分析本地成功但 CI 失败的问题

适用场景

  1. 01定位缺失包或版本冲突
  2. 02判断 C# 编译错误的来源
  3. 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.

诊断:

  1. 从错误中解析文件路径和行号——src/MyApp.Api/Services/OrderService.cs 第 42 行,第 17 列。
  2. CS0246 表示缺少类型。请检查:该类型是否已定义?是否导入了命名空间?项目是否引用了包含该类型的程序集?
  3. 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.

诊断:

  1. MSB4019:缺少 MSBuild .targets 文件。通常是 SDK 类型错误、缺少工作负载或 SDK 安装损坏所致。
  2. 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.

诊断:

  1. NU1101:包 ID 不存在。检查拼写、确认已配置包源,并检查包是否已重命名或弃用。
  2. NU1603:传递依赖版本冲突。某个包要求的版本高于最终解析的版本。
  3. 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

诊断:

  1. IDE0005:未使用的 using 指令。可以安全移除。
  2. IDE0044:字段只在构造函数中赋值,因此可以设为 readonly。
  3. 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)

诊断:

  1. CA1848:高性能日志记录。使用 [LoggerMessage] 源生成器特性,而不是在日志调用中使用字符串插值。
  2. CA2007:库代码的 ConfigureAwait(false) 指引。不适用于 ASP.NET Core 应用程序代码(没有 SynchronizationContext)。
  3. 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).

诊断:

  1. 包 ID 是否拼写正确?NuGet ID 不区分大小写,但必须完全匹配。
  2. 该包是否来自私有源?请检查 nuget.config 中的源配置。NuGet 会从项目目录开始,按层级向上搜索源。
  3. 是否配置了 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)

诊断:

  1. 两条依赖链要求同一包的不同主版本。
  2. 沿每条依赖链追踪,找出哪个顶级包固定在较旧版本。
  3. 通常只需升级较旧的顶级包即可修复。

修复模式:


<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.

诊断:

  1. 私有源的凭据缺失或已过期。
  2. 在 CI 中,检查是否已配置凭据提供程序或 PAT。
  3. 在本地,使用凭据运行 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]

诊断:

  1. 识别前缀:CA = 代码分析(.NET 分析器),IDE = IDE 代码样式分析器。
  2. 检查严重性:除非设置了 <TreatWarningsAsErrors>true</TreatWarningsAsErrors>,否则警告不会导致构建失败。
  3. 确定规则是否适用于你的项目类型(例如,CA2007 与 ASP.NET Core 无关,因为其中没有 SynchronizationContext)。
  4. 决定如何处理:修复代码、在 .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
何时可以接受抑制

仅当符合以下条件时,才可以接受抑制:

  1. 分析器无法理解代码的安全保证(例如,确保非 null 的自定义保护子句)。
  2. 该规则不适用于项目类型(例如,ASP.NET Core 应用中的 CA2007)。
  3. 提供有据可查的理由。
// 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.

诊断:

  1. 错误标记 [...csproj -> net8.0] 显示哪个 TFM 构建失败。net9.0 构建成功。
  2. GetAlternateLookup 是在 .NET 9 中添加的。代码使用了 .NET 8 不支持的 API。
  3. 修复需要使用条件编译,或为较旧的 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*.

诊断:

  1. 本地 SDK(9.0.200)包含 CI SDK(9.0.100)不支持的语言预览功能。
  2. 缺少 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

诊断:

  1. 本地已安装 MAUI/Aspire/WASM 工作负载,但 CI 映像中没有。
  2. 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.

诊断:

  1. 本地计算机此前还原时,已将该包放入全局 NuGet 缓存。
  2. CI 从空缓存开始,且找不到该包,因为未配置私有源。
  3. 仓库中缺少 nuget.config 文件,或 CI 缺少源的凭据。

修复模式:

  1. 在仓库根目录添加 nuget.config,列出所有必需的包源。
  2. 配置 CI 以通过凭据提供程序、PAT 或托管标识向私有源进行身份验证。
  3. CI 构建绝不能依赖全局 NuGet 缓存。
模式:特定操作系统的路径差异

示例场景:

Local (Windows):  Build succeeds
CI (Linux):       error MSB4018: The "ResolveAssemblyReference" task failed.
                  Could not find file '/src/MyApp/../Shared/MyLib.dll'

诊断:

  1. Windows 文件系统不区分大小写;Linux 区分大小写。
  2. 文件引用的大小写与磁盘上实际文件的大小写不同。
  3. 或者,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)

诊断:

  1. CI 流水线或 Directory.Build.props 通过仅适用于 CI 的条件启用了 <TreatWarningsAsErrors>true</TreatWarningsAsErrors>。
  2. 开发者在本地会看到警告,但因为构建成功而从不修复这些警告。

修复模式:

  • 在 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 选择、项目组织、多项目解决方案

参考资料

评论

支持 Markdown