.NET プロジェクト構造とビルド構成
このスキルを使用するタイミング
以下の場合にこのスキルを使用します。
- 最新のベストプラクティスで新しい.NETソリューションをセットアップするとき
- 複数のプロジェクトにわたるビルドプロパティを一元管理するとき
- 中央パッケージバージョン管理を実装するとき
- デバッグおよびNuGetパッケージ用のSourceLinkを設定するとき
- リリースノートを使用したバージョン管理を自動化するとき
- 一貫性のあるビルドのためにSDKバージョンを固定するとき
関連スキル
dotnet-local-tools- dotnet-tools.jsonを使用したローカル.NETツールの管理microsoft-extensions-configuration- 構成検証パターン
ソリューションファイル形式 (.slnx)
.slnx形式は、.NET 9で導入された最新のXMLベースのソリューションファイル形式です。従来の.sln形式を置き換えます。
従来の .sln に対する利点
| 項目 | .sln (レガシー) | .slnx (モダン) |
|---|---|---|
| 形式 | 独自テキスト形式 | 標準XML |
| 可読性 | GUID、難解な構文 | クリーンで人間が読める |
| バージョン管理 | 差分/マージが難しい | 差分/マージが簡単 |
| 編集 | IDE必須 | 任意のテキストエディタで可 |
バージョン要件
| ツール | 最小バージョン |
|---|---|
| .NET SDK | 9.0.200 |
| Visual Studio | 17.13 |
| MSBuild | Visual Studio Build Tools 17.13 |
注: .NET 10以降、dotnet new slnはデフォルトで.slnxファイルを作成します。.NET 9では、明示的に移行するか、形式を指定する必要があります。
例: .slnx ファイル
<Solution>
<Folder Name="/build/">
<File Path="Directory.Build.props" />
<File Path="Directory.Packages.props" />
<File Path="global.json" />
<File Path="NuGet.Config" />
<File Path="README.md" />
</Folder>
<Folder Name="/src/">
<Project Path="src/MyApp/MyApp.csproj" />
<Project Path="src/MyApp.Core/MyApp.Core.csproj" />
</Folder>
<Folder Name="/tests/">
<Project Path="tests/MyApp.Tests/MyApp.Tests.csproj" />
</Folder>
</Solution>
.sln から .slnx への移行
dotnet sln migrate コマンドを使用して既存のソリューションを変換します。
# 特定のソリューションファイルを移行
dotnet sln MySolution.sln migrate
# または、ディレクトリに .sln ファイルが1つしかない場合は、以下を実行:
dotnet sln migrate
重要: 同じリポジトリに .sln と .slnx の両方のファイルを保持しないでください。自動ソリューション検出に問題が発生し、同期の問題を引き起こす可能性があります。移行後は、古い .sln ファイルを削除してください。
Visual Studio で移行することもできます。
- ソリューションを開く
- ソリューションエクスプローラーでソリューションを選択
- ファイル > ソリューションの名前を付けて保存... に移動
- "ファイルの種類" を Xml ソリューションファイル (*.slnx) に変更
新しい .slnx ソリューションの作成
# .NET 10+: デフォルトで .slnx を作成
dotnet new sln --name MySolution
# .NET 9: 明示的に形式を指定
dotnet new sln --name MySolution --format slnx
# プロジェクトの追加 (両方の形式で同じように動作)
dotnet sln add src/MyApp/MyApp.csproj
推奨事項
.NET 9.0.200 以降を使用している場合は、ソリューションを .slnx に移行してください。 利点は非常に大きいです。
- マージ競合が劇的に減少(ランダムなGUIDが変更されない)
- 人間が読みやすく、任意のテキストエディタで編集可能
- 最新の
.csproj形式と一貫性がある - プルリクエストでの差分確認/レビュー体験が向上
Directory.Build.props
Directory.Build.props は、ディレクトリツリー内のすべてのプロジェクトに適用される一元化されたビルド構成を提供します。ソリューションルートに配置します。
完全な例
<Project>
<!-- メタデータ -->
<PropertyGroup>
<Authors>Your Team</Authors>
<Company>Your Company</Company>
<!-- 動的な著作権年 - 自動更新 -->
<Copyright>Copyright © 2020-$([System.DateTime]::Now.Year) Your Company</Copyright>
<Product>Your Product</Product>
<PackageProjectUrl>https://github.com/yourorg/yourrepo</PackageProjectUrl>
<RepositoryUrl>https://github.com/yourorg/yourrepo</RepositoryUrl>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageTags>your;tags;here</PackageTags>
</PropertyGroup>
<!-- C# 言語設定 -->
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<NoWarn>$(NoWarn);CS1591</NoWarn> <!-- XML コメントの欠落 -->
</PropertyGroup>
<!-- バージョン管理 -->
<PropertyGroup>
<VersionPrefix>1.0.0</VersionPrefix>
<PackageReleaseNotes>See RELEASE_NOTES.md</PackageReleaseNotes>
</PropertyGroup>
<!-- ターゲットフレームワーク定義 (再利用可能なプロパティ) -->
<PropertyGroup>
<NetStandardLibVersion>netstandard2.0</NetStandardLibVersion>
<NetLibVersion>net8.0</NetLibVersion>
<NetTestVersion>net9.0</NetTestVersion>
</PropertyGroup>
<!-- SourceLink 設定 -->
<PropertyGroup>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
</ItemGroup>
<!-- NuGet パッケージアセット -->
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)logo.png" Pack="true" PackagePath="\" />
<None Include="$(MSBuildThisFileDirectory)README.md" Pack="true" PackagePath="\" />
</ItemGroup>
<PropertyGroup>
<PackageIcon>logo.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>
<!-- グローバル using ステートメント -->
<ItemGroup>
<Using Include="System.Collections.Immutable" />
</ItemGroup>
</Project>
主要なパターン
動的な著作権年
<Copyright>Copyright © 2020-$([System.DateTime]::Now.Year) Your Company</Copyright>
MSBuild プロパティ関数を使用して、ビルド時に現在の年を挿入します。手動更新は不要です。
再利用可能なターゲットフレームワークプロパティ
ターゲットフレームワークを一度定義し、あらゆる場所で参照します:
<!-- Directory.Build.props 内 -->
<PropertyGroup>
<NetLibVersion>net8.0</NetLibVersion>
<NetTestVersion>net9.0</NetTestVersion>
</PropertyGroup>
<!-- MyApp.csproj 内 -->
<PropertyGroup>
<TargetFramework>$(NetLibVersion)</TargetFramework>
</PropertyGroup>
<!-- MyApp.Tests.csproj 内 -->
<PropertyGroup>
<TargetFramework>$(NetTestVersion)</TargetFramework>
</PropertyGroup>
NuGet パッケージ用 SourceLink
SourceLink は NuGet パッケージのステップスルーデバッグを可能にします:
<PropertyGroup>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
<ItemGroup>
<!-- ソース管理に適したプロバイダーを選択 -->
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
<!-- または: Microsoft.SourceLink.AzureRepos.Git -->
<!-- または: Microsoft.SourceLink.GitLab -->
<!-- または: Microsoft.SourceLink.Bitbucket.Git -->
</ItemGroup>
Directory.Packages.props - 中央パッケージ管理
中央パッケージ管理 (CPM) は、すべての NuGet パッケージバージョンの単一の信頼できる情報源を提供します。
設定
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<!-- 関連パッケージのバージョン変数を定義 -->
<PropertyGroup>
<AkkaVersion>1.5.35</AkkaVersion>
<AspireVersion>9.1.0</AspireVersion>
</PropertyGroup>
<!-- アプリケーション依存関係 -->
<ItemGroup Label="アプリ依存関係">
<PackageVersion Include="Akka" Version="$(AkkaVersion)" />
<PackageVersion Include="Akka.Cluster" Version="$(AkkaVersion)" />
<PackageVersion Include="Akka.Persistence" Version="$(AkkaVersion)" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
</ItemGroup>
<!-- ビルド/ツール依存関係 -->
<ItemGroup Label="ビルド依存関係">
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
</ItemGroup>
<!-- テスト依存関係 -->
<ItemGroup Label="テスト依存関係">
<PackageVersion Include="xunit" Version="2.9.3" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.0.1" />
<PackageVersion Include="FluentAssertions" Version="7.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageVersion Include="coverlet.collector" Version="6.0.3" />
</ItemGroup>
</Project>
パッケージの使用 (バージョン不要)
<!-- MyApp.csproj 内 -->
<ItemGroup>
<PackageReference Include="Akka" />
<PackageReference Include="Akka.Cluster" />
<PackageReference Include="Microsoft.Extensions.Hosting" />
</ItemGroup>
<!-- MyApp.Tests.csproj 内 -->
<ItemGroup>
<PackageReference Include="xunit" />
<PackageReference Include="FluentAssertions" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
</ItemGroup>
利点
- 単一の信頼できる情報源 - すべてのバージョンが1つのファイルに
- バージョンのずれなし - すべてのプロジェクトが同じバージョンを使用
- 簡単な更新 - 一度変更すれば、すべてに適用
- グループ化されたパッケージ - 関連パッケージのバージョン変数 (例: すべての Akka パッケージ)
global.json - SDKバージョンの固定
すべての環境で一貫性のあるビルドのために .NET SDK バージョンを固定します。
{
"sdk": {
"version": "9.0.200",
"rollForward": "latestFeature"
}
}
ロールフォワードポリシー
| ポリシー | 動作 |
|---|---|
disable | 正確なバージョンが必要 |
patch | 同じメジャー.マイナー、最新パッチ |
feature | 同じメジャー、最新マイナー.パッチ |
latestFeature | 同じメジャー、最新機能バンド |
minor | 同じメジャー、最新マイナー |
latestMinor | 同じメジャー、最新マイナー |
major | 最新 SDK (非推奨) |
推奨: latestFeature - 同じ機能バンド内のパッチ更新を許可します。
RELEASE_NOTES.md を使用したバージョン管理
リリースノートの形式
#### 1.2.0 2025年1月15日 ####
- 新しい機能Xを追加
- Yのバグを修正
- Zのパフォーマンスを改善
#### 1.1.0 2024年12月10日 ####
- 機能A、B、Cを含む初期リリース
解析スクリプト (getReleaseNotes.ps1)
function Get-ReleaseNotes {
param (
[Parameter(Mandatory=$true)]
[string]$MarkdownFile
)
$content = Get-Content -Path $MarkdownFile -Raw
$sections = $content -split "####"
$result = [PSCustomObject]@{
Version = $null
Date = $null
ReleaseNotes = $null
}
if ($sections.Count -ge 3) {
$header = $sections[1].Trim()
$releaseNotes = $sections[2].Trim()
$headerParts = $header -split " ", 2
if ($headerParts.Count -eq 2) {
$result.Version = $headerParts[0]
$result.Date = $headerParts[1]
}
$result.ReleaseNotes = $releaseNotes
}
return $result
}
バージョン更新スクリプト (bumpVersion.ps1)
function UpdateVersionAndReleaseNotes {
param (
[Parameter(Mandatory=$true)]
[PSCustomObject]$ReleaseNotesResult,
[Parameter(Mandatory=$true)]
[string]$XmlFilePath
)
$xmlContent = New-Object XML
$xmlContent.Load($XmlFilePath)
# VersionPrefix を更新
$versionElement = $xmlContent.SelectSingleNode("//VersionPrefix")
$versionElement.InnerText = $ReleaseNotesResult.Version
# PackageReleaseNotes を更新
$notesElement = $xmlContent.SelectSingleNode("//PackageReleaseNotes")
$notesElement.InnerText = $ReleaseNotesResult.ReleaseNotes
$xmlContent.Save($XmlFilePath)
}
ビルドスクリプト (build.ps1)
# ヘルパースクリプトを読み込む
. "$PSScriptRoot\scripts\getReleaseNotes.ps1"
. "$PSScriptRoot\scripts\bumpVersion.ps1"
# リリースノートを解析し、Directory.Build.props を更新
$releaseNotes = Get-ReleaseNotes -MarkdownFile (Join-Path -Path $PSScriptRoot -ChildPath "RELEASE_NOTES.md")
UpdateVersionAndReleaseNotes -ReleaseNotesResult $releaseNotes -XmlFilePath (Join-Path -Path $PSScriptRoot -ChildPath "Directory.Build.props")
Write-Output "バージョン $($releaseNotes.Version) に更新しました"
CI/CD 統合
# GitHub Actions の例
- name: リリースノートからバージョンを更新
shell: pwsh
run: ./build.ps1
- name: ビルド
run: dotnet build -c Release
- name: タグバージョンでパック
run: dotnet pack -c Release /p:PackageVersion=${{ github.ref_name }}
- name: NuGet にプッシュ
run: dotnet nuget push **/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json
NuGet.Config
NuGet ソースと動作を構成します:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<solution>
<add key="disableSourceControlIntegration" value="true" />
</solution>
<packageSources>
<clear />
<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>
</configuration>
主要な設定:
<clear />- 再現可能なビルドのために継承/デフォルトソースを削除disableSourceControlIntegration- TFS/Git 統合の問題を防ぐ
完全なプロジェクト構造
MySolution/
├── .config/
│ └── dotnet-tools.json # ローカル .NET ツール
├── .github/
│ └── workflows/
│ ├── pr-validation.yml # PR チェック
│ └── release.yml # NuGet への公開
├── scripts/
│ ├── getReleaseNotes.ps1 # RELEASE_NOTES.md の解析
│ └── bumpVersion.ps1 # Directory.Build.props の更新
├── src/
│ ├── MyApp/
│ │ └── MyApp.csproj
│ └── MyApp.Core/
│ └── MyApp.Core.csproj
├── tests/
│ └── MyApp.Tests/
│ └── MyApp.Tests.csproj
├── Directory.Build.props # 一元化されたビルド構成
├── Directory.Packages.props # 中央パッケージ管理
├── MySolution.slnx # ソリューションファイル
├── global.json # SDK バージョンの固定
├── NuGet.Config # NuGet ソース設定
├── RELEASE_NOTES.md # バージョン履歴
├── README.md # プロジェクトドキュメント
└── logo.png # NuGet パッケージアイコン