# 機能設計書 31-Microsoft.Extensions.DependencyInjection

## 概要

本ドキュメントは、Microsoft.Extensions.DependencyInjection（依存性注入）機能の設計内容を記述する。この機能は.NETアプリケーションにおける依存性注入（DI）コンテナの実装を提供し、オブジェクトのライフサイクル管理と依存関係の解決を自動化する。

### 本機能の処理概要

Microsoft.Extensions.DependencyInjectionは、.NETアプリケーションで広く使用される軽量なDI（Dependency Injection）コンテナ実装である。サービスの登録、解決、ライフタイム管理を統一的なAPIで提供する。

**業務上の目的・背景**：現代のソフトウェア開発において、疎結合なアーキテクチャを実現するためには依存性注入が不可欠である。このライブラリは、アプリケーション全体で一貫したDIパターンを提供し、テスタビリティの向上、モジュール性の確保、コードの保守性向上を実現する。特にASP.NET CoreやWorker Serviceなどのフレームワークで標準的に使用される。

**機能の利用シーン**：Webアプリケーション、バックグラウンドサービス、コンソールアプリケーション等、あらゆる.NETアプリケーションでサービスの登録と解決に利用される。コンストラクタインジェクション、メソッドインジェクション、プロパティインジェクションをサポートし、Singleton、Scoped、Transientの3種類のライフタイム管理を提供する。

**主要な処理内容**：
1. IServiceCollectionを通じたサービス記述子の登録
2. ServiceProviderの構築とサービスの解決
3. サービスライフタイム（Singleton/Scoped/Transient）の管理
4. コンストラクタインジェクションによる依存関係の自動解決
5. Keyedサービスによる名前付きサービス登録・解決
6. スコープの作成と管理

**関連システム・外部連携**：Microsoft.Extensions.Hosting、Microsoft.Extensions.Logging、Microsoft.Extensions.Configurationなど、Microsoft.Extensionsファミリーの各ライブラリと密接に連携する。また、Autofac、DryIoc、Grace、LightInjectなどのサードパーティDIコンテナとの互換性も提供する。

**権限による制御**：DIコンテナ自体は権限管理を行わないが、登録されたサービスが権限チェックを実装することで、アプリケーションレベルでのアクセス制御が可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 16 | BlazorBasicTestApp | 補助機能 | Blazorの依存性注入コンテナ |

## 機能種別

データ連携 / サービス管理 / ライフサイクル管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| serviceType | Type | Yes | 登録するサービスのインターフェース型 | null不可 |
| implementationType | Type | Yes | サービスの実装型 | null不可、serviceTypeに代入可能であること |
| lifetime | ServiceLifetime | Yes | サービスのライフタイム | Singleton/Scoped/Transientのいずれか |
| serviceKey | object | No | Keyedサービス用のキー | 任意のオブジェクト |
| implementationFactory | Func<IServiceProvider, object> | No | ファクトリ関数 | null許容 |
| implementationInstance | object | No | シングルトンインスタンス | null許容 |

### 入力データソース

- アプリケーションコードからのプログラマティックな登録
- IServiceCollectionへのサービス記述子追加

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ServiceProvider | IServiceProvider | 構築されたサービスプロバイダー |
| ResolvedService | object | 解決されたサービスインスタンス |
| ServiceScope | IServiceScope | 作成されたスコープ |

### 出力先

- アプリケーションのDIコンテナ
- 要求されたサービスインスタンス

## 処理フロー

### 処理シーケンス

```
1. サービス登録フェーズ
   └─ IServiceCollectionにServiceDescriptorを追加
2. ServiceProvider構築フェーズ
   └─ BuildServiceProvider()でCallSiteFactoryを初期化
3. サービス解決フェーズ
   └─ GetService<T>()でCallSiteを取得し、サービスをインスタンス化
4. スコープ管理フェーズ
   └─ CreateScope()で新しいServiceProviderEngineScopeを作成
5. 破棄フェーズ
   └─ Dispose()でスコープ内のIDisposableサービスを破棄
```

### フローチャート

```mermaid
flowchart TD
    A[サービス登録] --> B[ServiceCollection.Add]
    B --> C[BuildServiceProvider]
    C --> D{サービス要求}
    D -->|GetService| E[CallSiteFactory.GetCallSite]
    E --> F{キャッシュ確認}
    F -->|キャッシュあり| G[キャッシュから返却]
    F -->|キャッシュなし| H[サービスインスタンス生成]
    H --> I{ライフタイム判定}
    I -->|Singleton| J[Rootスコープに保存]
    I -->|Scoped| K[現在スコープに保存]
    I -->|Transient| L[毎回新規生成]
    J --> M[サービス返却]
    K --> M
    L --> M
    G --> M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-31-01 | ライフタイム制約 | ScopedサービスはSingletonから参照不可 | ValidateScopesが有効な場合 |
| BR-31-02 | 循環依存検出 | 循環参照を検出してエラーをスロー | サービス解決時 |
| BR-31-03 | コンストラクタ選択 | 最も多くのパラメータを持つ解決可能なコンストラクタを選択 | 複数コンストラクタ存在時 |
| BR-31-04 | Keyed Service | AnyKeyは列挙型サービスでのみ使用可能 | GetKeyedService呼び出し時 |

### 計算ロジック

サービス解決優先順位：
1. 登録された実装インスタンス
2. 登録されたファクトリ関数
3. 登録された実装型のコンストラクタインジェクション

## データベース操作仕様

該当なし（メモリ内操作のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | InvalidOperationException | 未登録サービスのGetRequiredService | サービスを登録する |
| - | InvalidOperationException | 循環依存検出時 | 依存関係を見直す |
| - | InvalidOperationException | Scopedサービスの不正アクセス | スコープを適切に作成する |
| - | ObjectDisposedException | 破棄済みプロバイダーへのアクセス | 新しいプロバイダーを使用する |

### リトライ仕様

リトライは不要（同期的なインメモリ操作）

## トランザクション仕様

該当なし

## パフォーマンス要件

- サービス解決: マイクロ秒オーダー
- 初回解決時にCallSiteをキャッシュし、以降の解決を高速化
- DynamicServiceProviderEngineによるIL/Expression Treeの動的生成で高速化

## セキュリティ考慮事項

- サービスインスタンスはスコープ外からアクセス不可
- IDisposableサービスは適切なタイミングで破棄される
- ValidateOnBuildオプションで起動時に設定エラーを検出可能

## 備考

- .NET 8以降でKeyedサービスが追加された
- NativeAOT環境ではDynamicEngineが無効化され、RuntimeServiceProviderEngineが使用される

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、サービス登録に使用されるデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ServiceDescriptor.cs | `src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceDescriptor.cs` | サービス登録情報を保持するクラス。ServiceType、ImplementationType、Lifetime等のプロパティを確認 |
| 1-2 | ServiceIdentifier.cs | `src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceIdentifier.cs` | サービス識別子の構造体。ServiceTypeとServiceKeyの組み合わせ |
| 1-3 | ServiceLifetime.cs | `src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceLifetime.cs` | Singleton/Scoped/Transientの列挙型定義 |

**読解のコツ**: ServiceDescriptorはサービス登録の「設計図」であり、実際のインスタンス生成方法を決定する。ImplementationType、ImplementationInstance、ImplementationFactoryの3パターンを理解することが重要。

#### Step 2: エントリーポイントを理解する

ServiceProviderの構築と基本的なサービス解決の流れを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ServiceProvider.cs | `src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs` | DIコンテナの中核クラス。GetService、GetKeyedServiceメソッドの実装を確認 |
| 2-2 | ServiceProviderOptions.cs | `src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProviderOptions.cs` | ValidateScopes、ValidateOnBuildなどのオプション |

**主要処理フロー**:
1. **52-96行目**: コンストラクタでCallSiteFactoryを初期化し、組み込みサービス（IServiceProvider、IServiceScopeFactory等）を登録
2. **103行目**: GetService()がServiceIdentifierを作成し、内部のGetServiceメソッドを呼び出し
3. **205-217行目**: サービス解決の実処理。ServiceAccessorを取得またはキャッシュし、RealizedServiceを呼び出し
4. **240-259行目**: CreateServiceAccessorでCallSiteを取得し、エンジンでサービスを実現

#### Step 3: サービス解決エンジンを理解する

CallSiteFactoryとServiceProviderEngineの動作を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | CallSiteFactory.cs | `src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs` | サービス解決の「レシピ」（CallSite）を生成するファクトリ |
| 3-2 | ServiceCallSite.cs | `src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceCallSite.cs` | CallSiteの基底クラス |
| 3-3 | ConstructorCallSite.cs | `src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ConstructorCallSite.cs` | コンストラクタインジェクション用CallSite |

**主要処理フロー**:
- **CallSiteFactory.GetCallSite()**: ServiceIdentifierからCallSiteを生成
- **コンストラクタ選択ロジック**: パラメータ数が最大で、全パラメータが解決可能なコンストラクタを選択

#### Step 4: ライフタイム管理を理解する

スコープとライフタイム管理の仕組みを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ServiceProviderEngineScope.cs | `src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs` | スコープの実装。ScopedサービスのキャッシュとDispose管理 |
| 4-2 | CallSiteRuntimeResolver.cs | `src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteRuntimeResolver.cs` | ランタイムでCallSiteを実行するビジター |

**主要処理フロー**:
- **ServiceProviderEngineScope.ResolvedServices**: Scopedサービスのキャッシュディクショナリ
- **VisitCache()**: キャッシュ場所（Root/Scope/None）に応じた保存処理

### プログラム呼び出し階層図

```
ServiceProvider.GetService(Type)
    │
    ├─ ServiceProvider.GetService(ServiceIdentifier, ServiceProviderEngineScope)
    │      │
    │      ├─ ConcurrentDictionary.GetOrAdd() → CreateServiceAccessor()
    │      │      │
    │      │      └─ CallSiteFactory.GetCallSite()
    │      │             │
    │      │             ├─ TryCreateExact() - 完全一致検索
    │      │             ├─ TryCreateOpenGeneric() - オープンジェネリック
    │      │             └─ TryCreateEnumerable() - IEnumerable<T>
    │      │
    │      └─ ServiceAccessor.RealizedService.Invoke(scope)
    │             │
    │             └─ ServiceProviderEngine.RealizeService()
    │                    │
    │                    ├─ RuntimeServiceProviderEngine
    │                    └─ DynamicServiceProviderEngine
    │                           │
    │                           └─ ILEmit/Expression Tree生成
    │
    └─ サービスインスタンス返却
```

### データフロー図

```
[入力]                    [処理]                         [出力]

ServiceDescriptor ───▶ ServiceCollection ───▶ CallSiteFactory
                                                    │
                                                    ▼
                                              CallSite生成
                                                    │
                                                    ▼
GetService(Type) ───▶ ServiceProvider ───▶ ServiceProviderEngine
                            │                       │
                            ▼                       ▼
                      スコープ判定            インスタンス生成
                            │                       │
                            ▼                       ▼
                      Root/Scope/None        キャッシュ保存
                            │                       │
                            └───────────────────────┘
                                        │
                                        ▼
                                 サービスインスタンス
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ServiceProvider.cs | `src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs` | ソース | DIコンテナの中核実装 |
| ServiceCollection.cs | `src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceCollection.cs` | ソース | サービス登録コレクション |
| ServiceDescriptor.cs | `src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceDescriptor.cs` | ソース | サービス記述子 |
| CallSiteFactory.cs | `src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs` | ソース | CallSite生成ファクトリ |
| ServiceProviderEngineScope.cs | `src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs` | ソース | スコープ管理 |
| CallSiteRuntimeResolver.cs | `src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteRuntimeResolver.cs` | ソース | ランタイム解決 |
| DynamicServiceProviderEngine.cs | `src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/DynamicServiceProviderEngine.cs` | ソース | 動的コード生成エンジン |
| ILEmitResolverBuilder.cs | `src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ILEmit/ILEmitResolverBuilder.cs` | ソース | IL生成 |
| ServiceProviderOptions.cs | `src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProviderOptions.cs` | ソース | プロバイダーオプション |
