- name
- wpf-clean-architecture-mvvm
- description
- Design guidelines for WPF applications using .NET 10 C#, MVVM Toolkit, Clean Architecture, Modular Monolith, and .NET Aspire. Use this skill when creating, modifying, or reviewing any part of this application's architecture, project structure, or code organization.
# WPF Clean Architecture + Modular Monolith + Aspire Design Guidelines
**.NET 10 C# + WPF** で **MVVM Toolkit**・**クリーンアーキテクチャ**・**モジュラーモノリス**・**.NET Aspire** を組み合わせて構築します。
## 参照ドキュメント
| ドキュメント | 内容 |
|---|---|
| [shell-pattern.md](references/shell-pattern.md) | IModule・IShellService のインターフェース定義と全実装例 |
| [aspire-integration.md](references/aspire-integration.md) | Aspire 統合の詳細設定・コード例 |
| [project-settings.md](references/project-settings.md) | 各プロジェクトの `.csproj` 設定とプロジェクト参照の例 |
---
## ソリューション構成
```
src/
AspireAppHost/ # Aspire オーケストレーター(バックエンドインフラ管理)
ServiceDefaults/ # OpenTelemetry・サービスディスカバリの共通設定
WpfApp/ # WPF シェル(最小限のグルーコードのみ)
Shared/
Shared.Kernel/ # ドメインプリミティブ(WPF 非依存)
Shared.UI/ # UI プリミティブ(IModule・IShellService・共通スタイル)
Modules/
{ModuleName}/
{ModuleName}.Domain/
{ModuleName}.Application/
{ModuleName}.Infrastructure/
{ModuleName}.Presentation/ # Views・ViewModels・IModule 実装
tests/
{ModuleName}.{Layer}.Tests/
```
---
## モジュラーモノリスのルール
- **モジュール間の直接参照は禁止**。モジュール間通信は `Shared.Kernel` 経由(イベント・インターフェース・共通 DTO)のみ。
- **UI もモジュールが所有する**。Views・ViewModels・ナビゲーション登録はすべて `Presentation` 層が管理する。
- **`WpfApp` は薄いシェルのみ**。`IModule` の列挙・初期化とシェル UI(ウィンドウ枠)だけを持ち、ビジネス知識を持たない。
- 各モジュールは DI 登録拡張メソッドを `Infrastructure` 層(`AddXxxModule`)と `Presentation` 層(`AddXxxPresentation`)にそれぞれ実装する。
---
## クリーンアーキテクチャ 各層の責務
| 層 | 依存先 | 主な内容 |
|---|---|---|
| **Domain** | `Shared.Kernel` のみ | エンティティ・値オブジェクト・集約ルート・リポジトリ IF・ドメイン例外 |
| **Application** | Domain・Shared.Kernel | コマンド/クエリ・ハンドラー・DTO・バリデーション・ドメインイベントハンドラー |
| **Infrastructure** | Application・Domain・Shared.Kernel | リポジトリ実装・EF Core・外部クライアント・DI 登録 |
| **Presentation** | Application・Shared.Kernel・Shared.UI | Views (XAML)・ViewModels (MVVM Toolkit)・`IModule` 実装・DI 登録 |
---
## MVVM Toolkit 使用規則
- ViewModel は `ObservableObject` を継承した `partial class` で定義する。
- プロパティは `[ObservableProperty]`(フィールド名 `_camelCase`)、コマンドは `[RelayCommand]` で生成する。
- プロパティ変更時の副作用は `partial void OnXxxChanged(T value)` で対応する。
- `CanExecute` は `[RelayCommand(CanExecute = nameof(CanXxx))]` で指定する。
- ViewModel と View は Presentation 層の `AddXxxPresentation()` で DI 登録する。
```csharp
public partial class OrderListViewModel(IOrderQueryService queryService) : ObservableObject
{
[ObservableProperty] private ObservableCollection<OrderDto> _orders = [];
[ObservableProperty] private bool _isLoading;
[RelayCommand]
private async Task LoadOrdersAsync(CancellationToken ct)
{
IsLoading = true;
try { Orders = new(await queryService.GetAllAsync(ct)); }
finally { IsLoading = false; }
}
}
```
---
## Shared.Kernel の内容(WPF 非依存)
`Entity<TId>`・`ValueObject`・`AggregateRoot<TId>`・`IDomainEvent`・`Result<T>`・共通例外基底・`IEventBus`
## Shared.UI の内容(WPF 依存)
`IModule`・`IShellService`・`NavigationItem`・共通 `ResourceDictionary`(テーマ・スタイル)・共通コンバーター基底
インターフェース定義と実装例 → [shell-pattern.md](references/shell-pattern.md)
---
## WpfApp(シェル)の責務
Generic Host (`Host.CreateApplicationBuilder()`) で起動し、`AddServiceDefaults()` を組み込む。
1. `ShellService` / `MainWindowViewModel` / `MainWindow` を DI 登録
2. 各モジュールの `AddXxxModule()` + `AddXxxPresentation()` を呼び出す
3. ビルド後、全 `IModule` を取得して `module.Initialize(shell)` を実行
4. `MainWindow` を表示する
完全なコード → [shell-pattern.md](references/shell-pattern.md)
---
## .NET Aspire 統合
- `AspireAppHost` はバックエンドインフラ(DB・API・キュー等)をオーケストレートする。WPF アプリは登録しない(手動起動)。
- `ServiceDefaults` を `WpfApp` から参照し、`AddServiceDefaults()` でテレメトリ・サービスディスカバリを有効化する。
- バックエンド API への接続は `https+http://{サービス名}` で行う(Aspire のサービスディスカバリ)。
詳細・コード例 → [aspire-integration.md](references/aspire-integration.md)
---
## 依存方向のルール(厳守)
```
Presentation → Application → Domain
Presentation → Shared.UI
Infrastructure → Application → Domain
WpfApp → {ModuleName}.Presentation(IModule 列挙のため)
WpfApp → Shared.UI
Shared.Kernel ← すべての層から参照可(UI 依存なし)
Shared.UI ← Presentation・WpfApp のみ参照可
AspireAppHost → バックエンドサービスプロジェクトのみ
モジュール間の直接参照 → 禁止
```
プロジェクトファイルと参照の設定例 → [project-settings.md](references/project-settings.md)
---
## コード生成時のチェックリスト
1. **新しいモジュール**: Domain → Application → Infrastructure → Presentation の順に4プロジェクトを作成し、Presentation から `Shared.UI` を参照する。
2. **ViewModel**: `ObservableObject` + `partial class` + `[ObservableProperty]`/`[RelayCommand]`。
3. **ナビゲーション画面の追加**: `IModule.Initialize()` に `NavigationItem` を登録し、View と ViewModel を DI 登録する。
4. **モジュール間通信**: `Shared.Kernel` の `IEventBus` や共通 DTO を経由する。モジュール直接参照は禁止。
5. **新しいユースケース**: Application 層にコマンド/クエリ+ハンドラーを追加し、ドメインロジックは Domain 層に保持する。
6. **バックエンドサービス追加**: `AspireAppHost` に登録し、Infrastructure 層で `https+http://{サービス名}` でアクセスする。
7. **新規プロジェクト作成**: `ServiceDefaults` を参照し、ホストビルダーで `AddServiceDefaults()` を呼び出す。
在 GitHub 查看