mcpField
P
project-structure

project-structure

github.com/wshaddix開発86536 回インストール35 週間前に更新
リポジトリ

project-structure について

.NET チーム向けに、ソリューション構成とビルド設定を整えるスキルです。共有 MSBuild 設定、NuGet バージョンの一元管理、SDK 固定、再現可能なビルド、リリースバージョン管理を扱います。

主な機能

  1. 01ソリューションとプロジェクトを構成
  2. 02MSBuild プロパティを一元管理
  3. 03NuGet バージョンを一元管理
  4. 04global.json で SDK を固定
  5. 05決定的ビルドを構成
  6. 06リリースノートからバージョンを管理

活用シーン

  1. 01新しい .NET ソリューションを構築
  2. 02複数プロジェクトの設定を統一
  3. 03パッケージのバージョンを統一
  4. 04CI の復元とビルドを再現可能にする

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/wshaddix/dotnet-skills --skill project-structure

インストール後、Claude Code で/project-structureを入力して読み込まれたか確認します。

詳細

.NET プロジェクトの構成とビルド設定

このスキルを使用するタイミング

以下の場合にこのスキルを使用します。

  • 最新のベストプラクティスに沿って新しい .NET ソリューションをセットアップする
  • 複数のプロジェクトに適用するビルドプロパティを一元管理する
  • パッケージバージョンの一元管理を導入する
  • デバッグと NuGet パッケージ向けに SourceLink をセットアップする
  • リリースノートを使ってバージョン管理を自動化する
  • 一貫したビルドのために SDK バージョンを固定する

推奨するソリューション構成

MyApp/
├── .config/
│   └── dotnet-tools.json           # Local .NET tools
├── .editorconfig
├── .gitignore
├── global.json
├── nuget.config
├── Directory.Build.props
├── Directory.Build.targets
├── Directory.Packages.props
├── MyApp.slnx                       # .NET 9+ SDK / VS 17.13+
├── src/
│   ├── MyApp.Core/
│   │   └── MyApp.Core.csproj
│   ├── MyApp.Api/
│   │   ├── MyApp.Api.csproj
│   │   ├── Program.cs
│   │   └── appsettings.json
│   └── MyApp.Infrastructure/
│       └── MyApp.Infrastructure.csproj
└── tests/
    ├── MyApp.UnitTests/
    │   └── MyApp.UnitTests.csproj
    └── MyApp.IntegrationTests/
        └── MyApp.IntegrationTests.csproj

主な原則:

  • src/ ディレクトリと tests/ ディレクトリを分ける
  • 関心事ごとにプロジェクトを分ける(Core/Domain、Infrastructure、API/Host)
  • ソリューションファイルをリポジトリのルートに配置する
  • 共通のビルド設定をすべてリポジトリのルートに配置する

ソリューションファイルの形式

.slnx(最新 — .NET 9+)

XML ベースのソリューション形式で、人が読みやすく、差分の確認に適しています。.NET 9+ SDK または Visual Studio 17.13+ が必要です。

<Solution>
  <Folder Name="/build/">
    <File Path="Directory.Build.props" />
    <File Path="Directory.Packages.props" />
    <File Path="global.json" />
    <File Path="NuGet.Config" />
  </Folder>
  <Folder Name="/src/">
    <Project Path="src/MyApp.Core/MyApp.Core.csproj" />
    <Project Path="src/MyApp.Api/MyApp.Api.csproj" />
    <Project Path="src/MyApp.Infrastructure/MyApp.Infrastructure.csproj" />
  </Folder>
  <Folder Name="/tests/">
    <Project Path="tests/MyApp.UnitTests/MyApp.UnitTests.csproj" />
    <Project Path="tests/MyApp.IntegrationTests/MyApp.IntegrationTests.csproj" />
  </Folder>
</Solution>
.sln から .slnx への移行
dotnet sln MySolution.sln migrate

重要: 同じリポジトリに .sln ファイルと .slnx ファイルの両方を残さないでください。

新しい .slnx ソリューションの作成
# .NET 10+: Creates .slnx by default
dotnet new sln --name MySolution

# .NET 9: Specify the format explicitly
dotnet new sln --name MySolution --format slnx

dotnet sln add src/MyApp/MyApp.csproj
メリット
  • マージの競合を大幅に減らせます
  • 人が読みやすく、編集できます
  • 最新の .csproj 形式との一貫性があります
  • プルリクエストでの差分確認やレビューがしやすくなります

Directory.Build.props

ディレクトリ配下のすべてのプロジェクトに適用される共通の MSBuild プロパティです。

<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>
  </PropertyGroup>

  
  <PropertyGroup>
    <LangVersion>latest</LangVersion>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
    <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
    <AnalysisLevel>latest-all</AnalysisLevel>
    <NoWarn>$(NoWarn);CS1591</NoWarn>
  </PropertyGroup>

  
  <PropertyGroup>
    <NetStandardLibVersion>netstandard2.0</NetStandardLibVersion>
    <NetLibVersion>net8.0</NetLibVersion>
    <NetTestVersion>net9.0</NetTestVersion>
  </PropertyGroup>

  
  <PropertyGroup>
    <PublishRepositoryUrl>true</PublishRepositoryUrl>
    <EmbedUntrackSources>true</EmbedUntrackSources>
    <IncludeSymbols>true</IncludeSymbols>
    <SymbolPackageFormat>snupkg</SymbolPackageFormat>
    <DebugType>embedded</DebugType>
    <ContinuousIntegrationBuild Condition="'$(CI)' == 'true'">true</ContinuousIntegrationBuild>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
  </ItemGroup>

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

  
  <ItemGroup>
    <Using Include="System.Collections.Immutable" />
  </ItemGroup>
</Project>
入れ子になった Directory.Build.props

内側のファイルは、外側のファイルを自動的にインポートしません。


<Project>
  <Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />
  <PropertyGroup>
    
  </PropertyGroup>
</Project>

Directory.Build.targets

プロジェクトの評価が完了した後にインポートされます。次の用途に使用します。

  • 共通のアナライザーパッケージ参照
  • カスタムビルドターゲット
  • プロジェクトの種類に基づく条件付きロジック
<Project>
  <ItemGroup>
    <PackageReference Include="Meziantou.Analyzer" PrivateAssets="all" />
    <PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" PrivateAssets="all" />
  </ItemGroup>
</Project>

Directory.Packages.props — パッケージの一元管理

CPM を使用すると、NuGet パッケージのバージョンをリポジトリのルートで一元管理できます。個々の .csproj ファイルでは、Version 属性を指定せずにパッケージを参照します。

<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
    <CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
  </PropertyGroup>

  <PropertyGroup>
    <AkkaVersion>1.5.35</AkkaVersion>
    <AspireVersion>9.1.0</AspireVersion>
  </PropertyGroup>

  <ItemGroup Label="App Dependencies">
    <PackageVersion Include="Akka" Version="$(AkkaVersion)" />
    <PackageVersion Include="Akka.Cluster" Version="$(AkkaVersion)" />
    <PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
  </ItemGroup>

  <ItemGroup Label="Test Dependencies">
    <PackageVersion Include="xunit.v3" Version="3.2.2" />
    <PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
    <PackageVersion Include="FluentAssertions" Version="7.0.0" />
    <PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
    <PackageVersion Include="coverlet.collector" Version="8.0.0" />
  </ItemGroup>

  <ItemGroup Label="Build Dependencies">
    <PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
  </ItemGroup>
</Project>
パッケージの使用(バージョン指定不要)

<ItemGroup>
  <PackageReference Include="Akka" />
  <PackageReference Include="Microsoft.Extensions.Hosting" />
</ItemGroup>
バージョンの上書き
<PackageReference Include="Newtonsoft.Json" VersionOverride="13.0.3" />

.editorconfig

一貫したコードスタイルを適用するため、リポジトリのルートに配置します。

root = true

[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.{csproj,props,targets,xml,json,yml,yaml}]
indent_size = 2

[*.cs]
csharp_style_namespace_declarations = file_scoped:warning
csharp_prefer_braces = true:warning
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
dotnet_style_require_accessibility_modifiers = always:warning
csharp_style_prefer_pattern_matching = true:suggestion
csharp_style_prefer_switch_expression = true:suggestion
csharp_using_directive_placement = outside_namespace:warning
dotnet_sort_system_directives_first = true

dotnet_naming_rule.private_fields_should_be_camel_case.symbols = private_fields
dotnet_naming_rule.private_fields_should_be_camel_case.style = camel_case_underscore
dotnet_naming_rule.private_fields_should_be_camel_case.severity = warning
dotnet_naming_symbols.private_fields.applicable_kinds = field
dotnet_naming_symbols.private_fields.applicable_accessibilities = private
dotnet_naming_style.camel_case_underscore.required_prefix = _
dotnet_naming_style.camel_case_underscore.capitalization = camel_case

global.json — SDK バージョンの固定

{
  "sdk": {
    "version": "9.0.200",
    "rollForward": "latestFeature"
  }
}
ロールフォワードポリシー
ポリシー動作
disable完全に一致するバージョンが必要
patch同じ major.minor の最新パッチバージョン
feature同じ major の最新 minor.patch バージョン
latestFeature同じ major の最新フィーチャーバンド
minor同じ major の最新 minor バージョン
latestMinor同じ major の最新 minor バージョン
major最新の SDK(推奨されません)

推奨: latestFeature — 同じフィーチャーバンド内でのパッチ更新を許可します。


nuget.config

パッケージソースとセキュリティを設定します。

<?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" />
  </packageSources>

  <packageSourceMapping>
    <packageSource key="nuget.org">
      <package pattern="*" />
    </packageSource>
  </packageSourceMapping>
</configuration>

<clear />、明示的なソース、<packageSourceMapping> を組み合わせるパターンにより、サプライチェーン攻撃を防止できます。

プライベートフィードの場合:

<packageSources>
  <clear />
  <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
  <add key="internal" value="https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json" />
</packageSources>
<packageSourceMapping>
  <packageSource key="nuget.org">
    <package pattern="*" />
  </packageSource>
  <packageSource key="internal">
    <package pattern="MyCompany.*" />
  </packageSource>
</packageSourceMapping>

NuGet Audit

.NET 9+ では、NuGetAudit がデフォルトで有効になっています。

<PropertyGroup>
  <NuGetAudit>true</NuGetAudit>
  <NuGetAuditLevel>low</NuGetAuditLevel>
  <NuGetAuditMode>all</NuGetAuditMode>
</PropertyGroup>

ロックファイル

再現性のある復元を有効にします。

<PropertyGroup>
  <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>

CI では:

dotnet restore --locked-mode

SourceLink と決定論的ビルド

NuGet に公開するライブラリの場合:

<PropertyGroup>
  <PublishRepositoryUrl>true</PublishRepositoryUrl>
  <EmbedUntrackSources>true</EmbedUntrackSources>
  <DebugType>embedded</DebugType>
  <ContinuousIntegrationBuild Condition="'$(CI)' == 'true'">true</ContinuousIntegrationBuild>
</PropertyGroup>
<ItemGroup>
  <PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="all" />
</ItemGroup>

RELEASE_NOTES.md によるバージョン管理

#### 1.2.0 January 15th 2025 ####

- Added new feature X
- Fixed bug in Y

#### 1.1.0 December 10th 2024 ####

- Initial release
CI/CD との統合
- name: Update version from release notes
  shell: pwsh
  run: ./build.ps1

- name: Build
  run: dotnet build -c Release

- name: Pack with tag version
  run: dotnet pack -c Release /p:PackageVersion=${{ github.ref_name }}

クイックリファレンス

ファイル用途
MySolution.slnx最新の XML ソリューションファイル
Directory.Build.propsビルドプロパティの一元管理
Directory.Packages.propsパッケージバージョンの一元管理
global.jsonSDK バージョンの固定
NuGet.Configパッケージソースの設定
RELEASE_NOTES.mdバージョン履歴
.editorconfigコードスタイルの適用
.config/dotnet-tools.jsonローカル .NET ツール

参考資料

コメント