dotnet-build-analysis について
.NETプロジェクトのMSBuild出力を解釈し、対処するためのスキルです。エラーコード、NuGet復元の失敗、アナライザー警告の例と、ローカルとCIで異なるビルド失敗の診断手順を扱います。
主な機能
- 01コンパイラーとMSBuildのエラー接頭辞を解釈
- 02NuGet復元エラーの診断
- 03アナライザー警告への対処を判断
- 04マルチターゲットビルドの差異を調査
- 05ローカルとCIのビルド失敗を分析
活用シーン
- 01パッケージ不足やバージョン競合の特定
- 02C#コンパイラーエラーの原因特定
- 03CIでのアナライザー警告への対処
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ wshaddix/ dotnet-skills --skill dotnet-build-analysisインストール後、Claude Code で/dotnet-build-analysisを入力して読み込まれたか確認します。
詳細
dotnet-build-analysis
概要/対象範囲
エージェントが MSBuild のビルド出力を解釈し、対処できるよう支援します。エラーコードのプレフィックス、NuGet の復元失敗、アナライザー警告の解釈、マルチターゲットビルドの差異、「ローカルでは動くが CI では失敗する」場合の診断パターンを扱います。各サブセクションには、出力例、診断手順、修正パターンが含まれます。
対象外: .csproj ファイルの作成または変更([skill:dotnet-csproj-reading] が担当)。プロジェクト構造の決定([skill:dotnet-project-structure] が担当)。エージェントによくあるコード上のミス([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 は null 許容参照型に関する警告です。このプロパティには
required修飾子、null 許容注釈(string?)、またはコンストラクターでの初期化が必要です。
修正パターン:
- CS0xxx(構文/型エラー):示された場所のソースコードを修正します。
usingディレクティブを追加し、型名を修正し、不足している参照を追加します。 - CS8xxx(null 許容に関する警告):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:明示的なダウングレードが検出されました。2 つのパッケージが、同じ依存関係の異なるバージョンを要求しています。
修正パターン:
- 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 アナライザーはコードスタイルを適用します。提案された変更を適用して修正してください。CI で警告をエラーに引き上げて適用するには、
.editorconfigで重大度を設定します。
CA -- .NET コード分析(FxCop/Microsoft.CodeAnalysis.NetAnalyzers)
API 設計、パフォーマンス、信頼性、セキュリティのルールを対象とする .NET コード分析 SDK アナライザーが出力します。
出力例:
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)
診断:
- 2 つの依存関係チェーンが、同じパッケージの異なるメジャーバージョンを要求しています。
- 各チェーンをたどり、どのトップレベルパッケージが古いバージョンに固定されているかを確認します。
- 通常は、古いトップレベルパッケージをアップグレードすれば解決します。
修正パターン:
<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 にバンドルされている、または NuGet 経由で追加された Roslyn アナライザーが出力します。修正するか、重大度を設定するかを適切に判断することが重要です。
出力例
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で重要度を設定します(以下を参照)。 - インラインで抑制するのは、根拠を文書化した場合に限ります(以下の「抑制が許容される場合」を参照)。
重要度レベル
| 重要度 | ビルドへの影響 | 対応 |
|---|---|---|
| Error | ビルドが失敗します | ビルドを成功させる前に修正する必要があります |
| Warning | ビルドが成功します(<TreatWarningsAsErrors>true</TreatWarningsAsErrors> が設定されている場合を除く) | 修正するか、.editorconfig で設定します |
| Suggestion | ビルドは成功し、IDE に表示されます | 可能であれば修正します |
| Hidden | 表示されませんが、コード修正機能から利用できます | リファクタリング中でなければ無視します |
重要度の設定
.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 の認証を設定します(Credential Provider、PAT、またはマネージド ID)。
- CI ビルドでグローバル NuGet キャッシュに依存してはいけません。
パターン:OS 固有のパスの違い
シナリオ例:
Local (Windows): Build succeeds
CI (Linux): error MSB4018: The "ResolveAssemblyReference" task failed.
Could not find file '/src/MyApp/../Shared/MyLib.dll'
診断:
- Windows のファイルシステムでは大文字と小文字が区別されませんが、Linux では区別されます。
- ファイル参照の大文字と小文字が、ディスク上の実際のファイルと異なっています。
- または、Linux で解決できないバックスラッシュのパス区切りが MSBuild プロパティで使われています。
修正パターン:
- ファイル名とディレクトリ名が、プロジェクト参照で使われている大文字と小文字に正確に一致するようにします。
.csprojのパスにはスラッシュ(/)を使用します。MSBuild はすべてのプラットフォームでこれを正規化します。- プッシュする前に、ローカルで
docker runを使って Linux コンテナー内でテストします。
パターン:CI のみでの TreatWarningsAsErrors
シナリオ例:
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 のアンチパターン
これらのパターンは、エージェントがビルドの問題を修正するのではなく、隠していることを示します。コードレビュー中にこれらを指摘してください。これらのパターンを検出する自動品質ゲートについては、[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] -- ビルドエラーを引き起こす、エージェントによくあるコーディングミス
- [skill:dotnet-csproj-reading] -- プロジェクトファイルの構造、PropertyGroup/ItemGroup の規則
- [skill:dotnet-project-structure] -- SDK の選択、プロジェクトの構成、マルチプロジェクトソリューション