mcpField
D
dotnet-solution-navigation

dotnet-solution-navigation

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

dotnet-solution-navigation について

.NET ソリューションの入口、ソリューションファイル、プロジェクト依存関係、設定ファイルを調べるエージェント向けスキルです。一般的な構成を見分けるためのコマンドと手がかりも示します。

主な機能

  1. 01アプリケーション入口の特定
  2. 02.sln と .slnx の読み取り
  3. 03プロジェクト依存関係の追跡
  4. 04設定ファイルの検索
  5. 05一般的なソリューション構成の判別

活用シーン

  1. 01不慣れな .NET リポジトリの把握
  2. 02共通変更の影響を受けるプロジェクトの特定
  3. 03実行時設定とビルド設定の検索

インストール

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

$npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-solution-navigation

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

詳細

dotnet-solution-navigation

概要/対象範囲

.NET ソリューション内での把握に役立つ情報をエージェントに提供します。エントリポイントの特定、ソリューションファイルの解析、プロジェクト依存関係のたどり方、構成ファイルの特定、一般的なソリューション構成の認識方法を扱います。各小節には、探索コマンドやヒューリスティックと出力例を含みます。

対象外: プロジェクトファイルの構成と変更([skill:dotnet-csproj-reading] が担当)。プロジェクト構成の判断と SDK の選択([skill:dotnet-project-structure] が担当)。テストフレームワークの構成とテスト種別の判断([skill:dotnet-testing-strategy] が担当)。

前提条件

.NET 8.0 以降の SDK。dotnet CLI が PATH 上で利用可能であること。SDK スタイルのプロジェクトに関する知識。

相互参照:[skill:dotnet-project-structure] はプロジェクト構成のガイダンス、[skill:dotnet-csproj-reading] はナビゲーション中に見つかった .csproj ファイルの読み取りと変更、[skill:dotnet-testing-strategy] はテストプロジェクトの特定とテスト種別の判断に関する情報を提供します。


小節 1:エントリポイントの特定

.NET アプリケーションには、いくつかの起動パターンがあります。すべてのアプリに従来型の Program.cs と Main メソッドがあるとは限りません。

パターン 1:Main メソッドを含む従来型の Program.cs

古いプロジェクト、ワーカーサービス、ホスティングを明示的に制御する必要がある場合に使用されます。

探索コマンド:

# Find Program.cs files containing a Main method
grep -rn "static.*void Main\|static.*Task Main\|static.*async.*Main" --include="*.cs" .

出力例:

src/MyApp.Worker/Program.cs:5:    public static async Task Main(string[] args)
src/MyApp.Console/Program.cs:3:    static void Main(string[] args)
パターン 2:トップレベルステートメント(C# 9 以降)

最新の .NET プロジェクト(.NET 6 以降のテンプレート)では、トップレベルステートメントを使用します。ファイルにはクラスや Main メソッドがなく、実行可能なコードだけが含まれます。

探索コマンド:

# Find Program.cs files that do NOT contain class/namespace declarations
# (top-level statements have no enclosing class)
for f in $(find . -name "Program.cs" -not -path "*/obj/*" -not -path "*/bin/*"); do
  if ! grep -Eq '^[[:space:]]*(class|namespace)[[:space:]]' "$f" 2>/dev/null; then
    echo "Top-level: $f"
  fi
done

出力例:

Top-level: ./src/MyApp.Api/Program.cs
Top-level: ./src/MyApp.Web/Program.cs

トップレベルの Program.cs によくある内容:

// No namespace, no class, no Main -- this IS the entry point
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
パターン 3:ワーカーサービスとバックグラウンドホスト

ワーカーサービスは、Web サーバーを使用せずに Host.CreateDefaultBuilder または Host.CreateApplicationBuilder を使用します。出力タイプが Exe で、SDK が Microsoft.NET.Sdk.Worker となっています。

探索コマンド:

# Find worker service projects by SDK type
grep -rn 'Sdk="Microsoft.NET.Sdk.Worker"' --include="*.csproj" .

# Or find IHostedService/BackgroundService implementations
grep -rn "BackgroundService\|IHostedService" --include="*.cs" . | grep -v "obj/" | grep -v "bin/"

出力例:

src/MyApp.Worker/MyApp.Worker.csproj:1:<Project Sdk="Microsoft.NET.Sdk.Worker">
src/MyApp.Worker/Services/OrderProcessor.cs:8:public class OrderProcessor : BackgroundService
src/MyApp.Worker/Services/EmailSender.cs:5:public class EmailSender : IHostedService
パターン 4:テストプロジェクト

テストプロジェクトは dotnet test のエントリポイントです。Program.cs がない場合もあります。エントリポイントはテストランナーが提供します。

探索コマンド:

# Find test projects by IsTestProject property or test SDK references
grep -rn "<IsTestProject>true</IsTestProject>" --include="*.csproj" .
grep -rn "Microsoft.NET.Test.Sdk\|xunit\|NUnit\|MSTest" --include="*.csproj" . | grep -v "obj/"  # Matches both xunit.v3 and legacy xunit

出力例:

tests/MyApp.Api.Tests/MyApp.Api.Tests.csproj:5:    <IsTestProject>true</IsTestProject>
tests/MyApp.Core.Tests/MyApp.Core.Tests.csproj:8:    <PackageReference Include="xunit.v3" />
概要ヒューリスティック

新しい .NET ソリューションを把握する際は、次のコマンドを順番に実行します。

# 1. Find all .csproj files
find . -name "*.csproj" -not -path "*/obj/*" | sort

# 2. Identify output types (Exe = app entry point, Library = dependency)
grep -rn "<OutputType>" --include="*.csproj" .

# 3. Find all Program.cs files
find . -name "Program.cs" -not -path "*/obj/*" -not -path "*/bin/*"

# 4. Identify test projects
grep -rn "<IsTestProject>true" --include="*.csproj" .

小節 2:ソリューションファイルの形式

.NET ソリューションでは、.sln(テキストベースのレガシー形式)または .slnx(XML ベースの .NET 9 以降のプレビュー形式)を使用します。どちらのファイルにも、プロジェクトとその関係が記載されています。

.sln 形式

従来のソリューション形式は、独自の構文を持つテキストファイルです(XML ではありません)。

探索および解析コマンド:

# Find solution files
find . -name "*.sln" -maxdepth 2

# List all projects in a solution using dotnet CLI
dotnet sln list
# Or specify the solution file explicitly:
dotnet sln MyApp.sln list

dotnet sln list の出力例:

Project(s)
----------
src/MyApp.Api/MyApp.Api.csproj
src/MyApp.Core/MyApp.Core.csproj
src/MyApp.Infrastructure/MyApp.Infrastructure.csproj
tests/MyApp.Api.Tests/MyApp.Api.Tests.csproj
tests/MyApp.Core.Tests/MyApp.Core.Tests.csproj

.sln ファイルを直接読む方法(dotnet sln list を利用できない場合に便利です):

# Extract project entries from .sln file
grep "^Project(" MyApp.sln

出力例:

Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyApp.Api", "src\MyApp.Api\MyApp.Api.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyApp.Core", "src\MyApp.Core\MyApp.Core.csproj", "{B2C3D4E5-F6A7-8901-BCDE-F12345678901}"

GUID {FAE04EC0-...} は C# プロジェクトを識別します。2 つ目の値は .csproj ファイルへの相対パスです。

.slnx 形式(.NET 9 以降)

.slnx 形式は、.NET 9 でプレビュー機能として導入された XML ベースのソリューションファイルです。

探索および解析コマンド:

# Find .slnx files
find . -name "*.slnx" -maxdepth 2

# dotnet sln commands work with .slnx files too
dotnet sln MyApp.slnx list

.slnx の内容例:

<Solution>
  <Folder Name="/src/">
    <Project Path="src/MyApp.Api/MyApp.Api.csproj" />
    <Project Path="src/MyApp.Core/MyApp.Core.csproj" />
  </Folder>
  <Folder Name="/tests/">
    <Project Path="tests/MyApp.Api.Tests/MyApp.Api.Tests.csproj" />
  </Folder>
</Solution>

.sln との主な違い:

機能.sln.slnx
形式独自のテキスト形式XML
読みやすさ低い(GUID、独自構文)高い(簡潔な XML)
利用可能なバージョンすべての .NET バージョン.NET 9 以降のプレビュー
ツール対応完全対応部分対応(拡大中)
ソリューションフォルダーGUID の入れ子参照<Folder> 要素
ソリューションファイルがない場合

リポジトリによっては、.sln を使わず個々の .csproj ファイルを使用します。プロジェクトディレクトリからビルドおよび実行します。

# If no .sln exists, find all .csproj files and build individually
find . -name "*.csproj" -not -path "*/obj/*" | sort
dotnet build src/MyApp.Api/MyApp.Api.csproj

小節 3:プロジェクト依存関係のたどり方

ProjectReference の連鎖を把握することは、ビルド順序の判断、共有コードの特定、変更の影響範囲の確認に欠かせません。

探索コマンド
# Find all ProjectReference entries across the solution
grep -rn "<ProjectReference" --include="*.csproj" . | grep -v "obj/"

出力例:

src/MyApp.Api/MyApp.Api.csproj:12:    <ProjectReference Include="../MyApp.Core/MyApp.Core.csproj" />
src/MyApp.Api/MyApp.Api.csproj:13:    <ProjectReference Include="../MyApp.Infrastructure/MyApp.Infrastructure.csproj" />
src/MyApp.Infrastructure/MyApp.Infrastructure.csproj:10:    <ProjectReference Include="../MyApp.Core/MyApp.Core.csproj" />
tests/MyApp.Api.Tests/MyApp.Api.Tests.csproj:14:    <ProjectReference Include="../../src/MyApp.Api/MyApp.Api.csproj" />
依存関係グラフの作成

上記の出力から、依存関係グラフは次のようになります。

MyApp.Api.Tests
  -> MyApp.Api
       -> MyApp.Core
       -> MyApp.Infrastructure
            -> MyApp.Core

dotnet list reference を使用した自動走査:

# List direct references for a specific project
dotnet list src/MyApp.Api/MyApp.Api.csproj reference

出力例:

Project reference(s)
--------------------
../MyApp.Core/MyApp.Core.csproj
../MyApp.Infrastructure/MyApp.Infrastructure.csproj

推移的な依存関係の完全な分析:

# Build the full dependency tree by traversing transitively
# Start from the top-level project and follow each reference
dotnet list src/MyApp.Api/MyApp.Api.csproj reference
dotnet list src/MyApp.Infrastructure/MyApp.Infrastructure.csproj reference
# Continue until you reach projects with no ProjectReference entries
影響分析

MyApp.Core のような共有プロジェクトを変更すると、そのプロジェクトを直接または推移的に参照するすべてのプロジェクトに影響します。

# Find all projects that reference a specific project
grep -rn "MyApp.Core.csproj" --include="*.csproj" . | grep -v "obj/"

出力例:

src/MyApp.Api/MyApp.Api.csproj:12:    <ProjectReference Include="../MyApp.Core/MyApp.Core.csproj" />
src/MyApp.Infrastructure/MyApp.Infrastructure.csproj:10:    <ProjectReference Include="../MyApp.Core/MyApp.Core.csproj" />
tests/MyApp.Core.Tests/MyApp.Core.Tests.csproj:14:    <ProjectReference Include="../../src/MyApp.Core/MyApp.Core.csproj" />

つまり、MyApp.Core を変更した場合は、MyApp.Api、MyApp.Infrastructure、MyApp.Core.Tests をテストする必要があります。


サブセクション 4:構成ファイルの場所

.NET プロジェクトでは、ソリューション内のさまざまな場所に複数の構成ファイルが配置されています。アプリケーションの動作を理解するには、これらのファイルの場所を把握することが不可欠です。

appsettings*.json

検出コマンド:

# Find all appsettings files
find . -name "appsettings*.json" -not -path "*/obj/*" -not -path "*/bin/*" | sort

出力例:

./src/MyApp.Api/appsettings.json
./src/MyApp.Api/appsettings.Development.json
./src/MyApp.Api/appsettings.Production.json
./src/MyApp.Worker/appsettings.json

主な動作: 環境固有のファイル(appsettings.{ENVIRONMENT}.json)は、ベースとなる appsettings.json の値を上書きします。環境は DOTNET_ENVIRONMENT または ASPNETCORE_ENVIRONMENT で設定します。

launchSettings.json

検出コマンド:

# Find launch settings (inside Properties/ folder of each project)
find . -name "launchSettings.json" -not -path "*/obj/*" -not -path "*/bin/*"

出力例:

./src/MyApp.Api/Properties/launchSettings.json
./src/MyApp.Web/Properties/launchSettings.json

主な動作: dotnet run と Visual Studio で使用され、起動プロファイル(ポート、環境変数、起動 URL)を構成します。本番環境にはデプロイされません。

Directory.Build.props と Directory.Build.targets

検出コマンド:

# Find all Directory.Build.props/targets files (may exist at multiple levels)
find . -name "Directory.Build.props" -o -name "Directory.Build.targets" | sort

出力例:

./Directory.Build.props
./Directory.Build.targets
./src/Directory.Build.props
./tests/Directory.Build.props

主な動作: MSBuild は、プロジェクトディレクトリから上位へたどって見つかった最も近いファイルをインポートします。ネストされたファイルは、親ファイルを明示的にインポートしない限り、親ファイルをシャドーします(連鎖については [skill:dotnet-csproj-reading] を参照してください)。

その他の構成ファイル
# Find all .NET configuration files in one sweep
find . \( -name "nuget.config" -o -name "global.json" -o -name ".editorconfig" \
  -o -name "Directory.Packages.props" \) -not -path "*/obj/*" | sort

出力例:

./.editorconfig
./Directory.Packages.props
./global.json
./nuget.config
./src/.editorconfig
ファイル目的解決方法
nuget.configNuGet パッケージソースとマッピングプロジェクトディレクトリから上位へ階層的に検索
global.jsonSDK バージョンの固定上位へたどって最も近いファイルを検索
.editorconfigコードスタイルとアナライザーの重大度階層的に適用(セクションは上位の設定とマージ)
Directory.Packages.propsパッケージバージョンの一元管理プロジェクトディレクトリから上位へ階層的に検索

サブセクション 5:一般的なソリューション構成

構成パターンを見分けることで、エージェントは不慣れなコードベースをよりすばやく把握できます。

パターン 1:src/tests 構成

最も一般的な構成です。ソースプロジェクトを src/ に、テストプロジェクトを tests/ に配置し、名前を対応させます。

MyApp/
  MyApp.sln
  Directory.Build.props
  Directory.Packages.props
  global.json
  nuget.config
  .editorconfig
  src/
    MyApp.Api/
      MyApp.Api.csproj
      Program.cs
      Controllers/
      Services/
    MyApp.Core/
      MyApp.Core.csproj
      Models/
      Interfaces/
    MyApp.Infrastructure/
      MyApp.Infrastructure.csproj
      Data/
      Repositories/
  tests/
    MyApp.Api.Tests/
      MyApp.Api.Tests.csproj
    MyApp.Core.Tests/
      MyApp.Core.Tests.csproj
  docs/
    architecture.md

目安:

  • ルートレベルに src/ と tests/ ディレクトリがある。
  • テストプロジェクト名は、ソースプロジェクト名に .Tests を付けたものになっている。
  • 共有ビルド構成(Directory.Build.props、global.json)がルートにある。

検出:

# Detect src/tests layout
ls -d src/ tests/ 2>/dev/null && echo "src/tests layout detected"
パターン 2:垂直スライス構成

技術レイヤーではなく、機能ごとにコードを整理します。各スライスには、それぞれのモデル、ハンドラー、エンドポイントが含まれます。

MyApp/
  MyApp.sln
  src/
    MyApp.Api/
      MyApp.Api.csproj
      Program.cs
      Features/
        Orders/
          CreateOrder.cs          # Handler + request + response
          GetOrder.cs
          OrderValidator.cs
          OrderEndpoints.cs       # Minimal API endpoint mapping
        Products/
          CreateProduct.cs
          ListProducts.cs
          ProductEndpoints.cs
      Common/
        Behaviors/
          ValidationBehavior.cs
        Middleware/
          ExceptionMiddleware.cs
  tests/
    MyApp.Api.Tests/
      Features/
        Orders/
          CreateOrderTests.cs
          GetOrderTests.cs

目安:

  • プロジェクト内に Features/ ディレクトリがある。
  • 各機能フォルダーに、関連する複数のファイル(ハンドラー、バリデーター、エンドポイント)が含まれている。
  • テストのフォルダー構成が機能フォルダーの構成と対応している。

検出:

# Detect vertical slice layout
find . -type d -name "Features" -not -path "*/obj/*" -not -path "*/bin/*"
パターン 3:モジュラーモノリス

単一のソリューション内で、複数の境界づけられたコンテキストを個別のプロジェクトとして構成し、明示的なインターフェイスまたは共有メッセージバスを介して連携します。

MyApp/
  MyApp.sln
  src/
    MyApp.Host/
      MyApp.Host.csproj          # Composition root -- references all modules
      Program.cs
    Modules/
      Ordering/
        MyApp.Ordering/
          MyApp.Ordering.csproj
          OrderingModule.cs       # Module registration (DI, endpoints)
          Domain/
          Application/
          Infrastructure/
        MyApp.Ordering.Tests/
      Catalog/
        MyApp.Catalog/
          MyApp.Catalog.csproj
          CatalogModule.cs
          Domain/
          Application/
          Infrastructure/
        MyApp.Catalog.Tests/
    MyApp.Shared/
      MyApp.Shared.csproj        # Cross-cutting contracts (events, interfaces)

目安:

  • 自己完結した境界づけられたコンテキストを含む Modules/ ディレクトリがある。
  • すべてのモジュールを参照する Host または Startup プロジェクトがある。
  • モジュール間で共有するコントラクト用の Shared プロジェクトがある。

検出:

# Detect modular monolith layout
find . -type d -name "Modules" -not -path "*/obj/*" -not -path "*/bin/*"
# Or look for module registration patterns
grep -rn "Module\|AddModule\|RegisterModule" --include="*.cs" . | grep -v "obj/" | head -10

Slopwatch のアンチパターン

テストプロジェクトの検出時にこれらのパターンが見られる場合、エージェントがテストの不足に対処せず、隠していることを示しています。これらのパターンを検出する自動品質ゲートについては、[skill:dotnet-slopwatch] を参照してください。

テストプロジェクトの検出で無効化またはスキップされているテスト

ソリューションを確認してテストプロジェクトを特定する際は、存在するにもかかわらず、ひそかに無効化されているテストに注意してください。

// RED FLAG: skipped tests that will not run during dotnet test
[Fact(Skip = "Flaky -- revisit later")]
public async Task ProcessOrder_ConcurrentRequests_HandledCorrectly() { }

// RED FLAG: entire test class disabled via conditional compilation
#if false
public class OrderIntegrationTests
{
    [Fact]
    public async Task CreateOrder_PersistsToDatabase() { }
}
#endif

// RED FLAG: commented-out test methods
// [Fact]
// public void CalculateDiscount_NegativeAmount_ThrowsException() { }

無効化されているテストを確認するための検出コマンド:

# Find skipped tests
grep -rEn 'Skip[[:space:]]*=' --include="*.cs" . | grep -v "obj/" | grep -v "bin/"

# Find tests hidden behind #if false
grep -rn "#if false" --include="*.cs" . | grep -v "obj/" | grep -v "bin/"

# Find commented-out test attributes
grep -rEn '//[[:space:]]*\[(Fact|Theory|Test)\]' --include="*.cs" . | grep -v "obj/" | grep -v "bin/"

修正方法: テストが無効化されている理由を調べてください。タイミングが原因で不安定になっている場合は、非決定性を解消するか、[Retry](xUnit v3)を使用してください。削除された機能をテストしている場合は、テストを削除してください。無効化されたテストを、見えない技術的負債として決して放置しないでください。


相互参照

  • [skill:dotnet-project-structure] -- プロジェクトの構成、SDK の選択、ソリューションのレイアウトに関する判断
  • [skill:dotnet-csproj-reading] -- 確認中に見つかった .csproj ファイルの読み取りと変更
  • [skill:dotnet-testing-strategy] -- テストプロジェクトの特定、テストの種類、テストの整理

参考資料

コメント