dotnet-csproj-reading について
SDK形式の.csprojファイルを読み、安全に変更する開発者やエージェント向けのスキルです。MSBuildのプロパティや項目、条件、共有設定、パッケージの一元管理を扱います。
主な機能
- 01SDK形式プロジェクト構造の理解
- 02PropertyGroupとItemGroupの変更
- 03条件式とマルチターゲット設定の把握
- 04Directory.Build.propsとtargetsの設定
- 05Directory.Packages.propsによるバージョン管理
- 06警告抑制のアンチパターンの特定
活用シーン
- 01NuGetパッケージやプロジェクト参照の追加
- 02ターゲットフレームワークとビルド設定の変更
- 03ソリューションでのパッケージ一元管理の導入
- 04プロジェクト設定に関する一般的なミスの調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ wshaddix/ dotnet-skills --skill dotnet-csproj-readingインストール後、Claude Code で/dotnet-csproj-readingを入力して読み込まれたか確認します。
詳細
dotnet-csproj-reading
概要/対象範囲
エージェントが SDK スタイルの .csproj ファイルを読み取り、安全に変更できるようにします。プロジェクト構造、PropertyGroup の規約、ItemGroup のパターン、条件式、Directory.Build.props/.targets、セントラルパッケージ管理(Directory.Packages.props)を扱います。各サブセクションでは、注釈付きの XML の例と一般的な変更パターンを示します。
対象外: プロジェクトの構成と SDK の選択([skill:dotnet-project-structure] が担当)。ビルドエラーの解釈([skill:dotnet-build-analysis] が担当)。エージェントがよく犯すコーディングミス([skill:dotnet-agent-gotchas] が担当)。
前提条件
.NET 8.0 以降の SDK。SDK スタイルのプロジェクトのみ(従来形式の .csproj は対象外)。MSBuild(.NET SDK に含まれています)。
相互参照:[skill:dotnet-project-structure] はプロジェクトの構成と SDK の選択について、[skill:dotnet-build-analysis] はプロジェクトの設定ミスによるビルドエラーの解釈について、[skill:dotnet-agent-gotchas] はエージェントがよく犯すプロジェクト構造上のミスについて説明しています。
サブセクション 1:SDK スタイルのプロジェクト構造
SDK スタイルのプロジェクトでは、何百もの既定のターゲットと props をインポートする <Project Sdk="..."> 宣言を使用します。SDK が暗黙的に提供する内容を理解することは、冗長または競合する宣言を避けるために不可欠です。
注釈付き XML の例
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>
</Project>
一般的な変更パターン
SDK の種類を変更する -- エージェントが誤った SDK で Web プロジェクトを作成した場合:
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk.Web">
既定の glob を無効にする -- まれですが、従来形式から移行する場合や、ファイルを明示的に管理する必要がある場合に必要です:
<PropertyGroup>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<EnableDefaultItems>false</EnableDefaultItems>
</PropertyGroup>
プロジェクトが使用する SDK を確認する:
# Check the first line of the .csproj for the Sdk attribute
head -1 src/MyApp/MyApp.csproj
# Output: <Project Sdk="Microsoft.NET.Sdk.Web">
サブセクション 2:PropertyGroup の規約
PropertyGroup 要素には、スカラー値の MSBuild プロパティが含まれます。最も重要なプロパティは、ターゲット フレームワーク、言語機能、出力の種類を制御します。
注釈付き XML の例
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<OutputType>Exe</OutputType>
<RootNamespace>MyApp.Api</RootNamespace>
<AssemblyName>MyApp.Api</AssemblyName>
<LangVersion>preview</LangVersion>
</PropertyGroup>
一般的な変更パターン
既存のプロジェクトで nullable を有効にする:
<Nullable>enable</Nullable>
コンソールアプリの出力の種類を設定する:
<OutputType>Exe</OutputType>
TreatWarningsAsErrors を追加する(CI との一貫性を保つため推奨):
<PropertyGroup>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
サブセクション 3:ItemGroup のパターン
ItemGroup 要素には、パッケージ参照、プロジェクト参照、ファイルのインクルード、その他のビルド項目などのコレクションが含まれます。主要な 3 種類の項目を理解すると、エージェントによくあるミスを防げます。
注釈付き XML の例
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
<PackageReference Include="Nerdbank.GitVersioning" Version="3.7.115"
PrivateAssets="All" IncludeAssets="runtime;build;native;analyzers" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../MyApp.Core/MyApp.Core.csproj" />
<ProjectReference Include="../MyApp.Internal/MyApp.Internal.csproj"
PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<None Include="appsettings.json" CopyToOutputDirectory="PreserveNewest" />
<Content Include="wwwroot/**" CopyToOutputDirectory="PreserveNewest" />
<EmbeddedResource Include="Resources/**/*.resx" />
</ItemGroup>
一般的な変更パターン
NuGet パッケージを追加する:
# Prefer CLI to avoid formatting issues
dotnet add src/MyApp/MyApp.csproj package Microsoft.EntityFrameworkCore --version 9.0.0
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
プロジェクト参照を追加する:
# CLI ensures correct relative path
dotnet add src/MyApp.Api/MyApp.Api.csproj reference src/MyApp.Core/MyApp.Core.csproj
<ProjectReference Include="../MyApp.Core/MyApp.Core.csproj" />
コンパイル対象外のファイルを出力に含める:
<None Update="config/*.json" CopyToOutputDirectory="PreserveNewest" />
サブセクション 4:条件式とマルチターゲット
MSBuild の条件を使うと、TFM 固有のプロパティ、プラットフォーム固有のパッケージ参照、ビルド構成ロジックを設定できます。条件の構文を理解すると、マルチターゲットのビルドが壊れるのを防げます。
注釈付き XML の例
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'net9.0'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="Backport.System.Threading.Lock" Version="2.0.5" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('net9.0-android'))">
<PackageReference Include="Xamarin.AndroidX.Core" Version="1.15.0.1" />
</ItemGroup>
<PropertyGroup Condition="'$(CI)' == 'true'">
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>
</Project>
一般的な変更パターン
TFM を追加する:
<TargetFramework>net8.0</TargetFramework>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
プラットフォーム検出にバージョン非依存の TFM パターンを使用する:
<ItemGroup Condition="$(TargetFramework.Contains('-android'))">
<AndroidResource Include="Resources/**" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net9.0-android'">
条件構文のリファレンス:
| 式 | 意味 |
|---|---|
'$(Prop)' == 'value' | 完全一致(大文字と小文字を区別しない) |
'$(Prop)' != 'value' | 等しくない |
$(Prop.StartsWith('prefix')) | 文字列が指定した文字列で始まる |
$(Prop.Contains('sub')) | 文字列に指定した文字列が含まれる |
'$(Prop)' == '' | プロパティが空、または未設定 |
Exists('path') | ファイルまたはディレクトリが存在する |
サブセクション 5:Directory.Build.props と Directory.Build.targets
これらのファイルを使って、共通のビルド構成を一元管理できます。MSBuild は、現在のディレクトリからファイルシステムのルートまで、現在のディレクトリとすべての親ディレクトリにある Directory.Build.props(プロジェクトの前)と Directory.Build.targets(プロジェクトの後)を自動的にインポートします。
注釈付き XML:Directory.Build.props
<Project>
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Deterministic>true</Deterministic>
<ContinuousIntegrationBuild Condition="'$(CI)' == 'true'">true</ContinuousIntegrationBuild>
</PropertyGroup>
<PropertyGroup>
<Authors>MyCompany</Authors>
<Company>MyCompany</Company>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
</Project>
注釈付き XML:Directory.Build.targets
<Project>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="9.0.0"
PrivateAssets="All" IncludeAssets="analyzers" />
</ItemGroup>
<ItemGroup Condition="'$(IsTestProject)' == 'true'">
<PackageReference Include="coverlet.collector" Version="8.0.0"
PrivateAssets="All" />
</ItemGroup>
<Target Name="PrintBuildInfo" AfterTargets="Build">
<Message Importance="high" Text="Built $(AssemblyName) for $(TargetFramework)" />
</Target>
</Project>
よくある変更パターン
階層と上書き動作:
repo-root/
Directory.Build.props <-- applies to ALL projects
src/
Directory.Build.props <-- applies to src/ projects only
MyApp.Api/
MyApp.Api.csproj <-- inherits from src/ props (NOT repo-root/)
MSBuild は上位ディレクトリをたどって、最も近い Directory.Build.props をインポートします。ネストされた Directory.Build.props がある場合、親のファイルはシャドウされます。両方を連結するには、ネストされたファイルで親のファイルを明示的にインポートする必要があります。
<Project>
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />
<PropertyGroup>
<RootNamespace>MyApp.$(MSBuildProjectName)</RootNamespace>
</PropertyGroup>
</Project>
.props と .targets の使い分け:
| .props を使う場合 | .targets を使う場合 |
|---|---|
| プロパティの既定値(TFM、nullable など) | プロジェクトのプロパティに依存する項目 |
| パッケージのメタデータ(作成者、ライセンス) | カスタムビルドターゲット(AfterTargets、BeforeTargets) |
| プロジェクト側で上書きできるプロパティ | すべてのプロジェクトに追加するアナライザーパッケージ |
サブセクション 6:Directory.Packages.props(集中型パッケージ管理)
集中型パッケージ管理(CPM)では、NuGet パッケージのバージョンを単一の Directory.Packages.props ファイルで一元管理します。個々のプロジェクトでは、バージョンを指定せずにパッケージを参照します。
注釈付き XML の例
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
<PackageVersion Include="Serilog.AspNetCore" Version="8.0.3" />
<PackageVersion Include="xunit.v3" Version="3.2.2" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageVersion Include="NSubstitute" Version="5.3.0" />
</ItemGroup>
</Project>
CPM を有効にしたプロジェクトファイル:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" />
</ItemGroup>
</Project>
よくある変更パターン
既存のソリューションで CPM を有効にする:
- ソリューションのルートに
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>を含むDirectory.Packages.propsを作成します。 - すべての
PackageReference項目からVersion属性を、中央ファイル内のPackageVersionエントリに移します。 - 個々の
.csprojファイル内のすべてのPackageReference項目からVersionを削除します。
# Find all PackageReference entries with Version attributes
grep -rn 'PackageReference Include=.*Version=' --include="*.csproj" src/
特定のプロジェクトでバージョンを上書きする場合(例外的な回避策):
<PackageReference Include="Microsoft.EntityFrameworkCore" VersionOverride="8.0.11" />
階層的な解決: Directory.Packages.props は、Directory.Build.props と同様に、プロジェクトのディレクトリから上位へたどって解決されます。モノレポでは、中央ファイルをリポジトリのルートに配置します。サブディレクトリに独自の Directory.Packages.props を配置することもできます。最も近いファイルが優先されます。
プロジェクトごとのバージョン指定から移行する:
# List all unique packages and versions across the solution
dotnet list src/MyApp.sln package --format json
# Use this output to build the central PackageVersion list
Slopwatch のアンチパターン
プロジェクトファイル内に次のパターンがある場合、エージェントが問題を修正せずに隠している可能性があります。これらのパターンを検出する自動品質ゲートについては、[skill:dotnet-slopwatch] を参照してください。
.csproj 内の NoWarn
<PropertyGroup>
<NoWarn>CS8600;CS8602;CS8604;IL2026;IL2046;IL3050</NoWarn>
</PropertyGroup>
プロジェクトファイル内の <NoWarn> は、プロジェクト全体の警告を抑制し、問題を見えなくします。スコープの境界がなく、ファイルごとに監査できないため、#pragma よりも問題があります。
修正方法: <NoWarn> エントリを削除し、根本的な問題を修正します。プロジェクト全体には適用されない警告については、代わりに .editorconfig で重大度を設定します。
# .editorconfig -- preferred over <NoWarn> for controlled suppression
[*.cs]
dotnet_diagnostic.CA2007.severity = none # No SynchronizationContext in ASP.NET Core
Directory.Build.props 内で抑制されたアナライザー
<PropertyGroup>
<NoWarn>$(NoWarn);CA1062;CA1822;CA2007</NoWarn>
<RunAnalyzers>false</RunAnalyzers>
<EnableNETAnalyzers>false</EnableNETAnalyzers>
</PropertyGroup>
Directory.Build.props でアナライザーを無効にすると、後から追加された新しいプロジェクトも含め、ソリューション内のすべてのプロジェクトでアナライザーが無効になります。エージェントが手早くビルドをクリーンにするために、この方法を使うことがあります。
修正方法: アナライザーは全体で有効にしたままにします。警告にはプロジェクトごと、またはファイルごとに対処します。特定のルールカテゴリが適用されない場合(例:ASP.NET Core アプリでの CA2007)は、適切なスコープの .editorconfig で、理由を説明するコメントを添えて抑制します。
相互参照
- [skill:dotnet-project-structure] -- SDK の選択、プロジェクトの構成、ソリューションのレイアウト
- [skill:dotnet-build-analysis] -- プロジェクト設定の誤りによって発生したビルドエラーの解釈
- [skill:dotnet-agent-gotchas] -- エージェントがよく起こすプロジェクト構成上のミス(誤った SDK、壊れた参照)