基本概念MediatRは、アプリケーションにおけるリクエストと通知の処理を実装するためのオープンソースのメディエーターパターンライブラリです。以下の基本コンポーネントを提供します。 - メディエーター:リクエストと通知の処理を調整します。MediatRライブラリの中核コンポーネントであり、リクエストと通知を適切なハンドラーに送信することで、分離と論理的な処理を実現します。
- リクエスト処理:MediaTekは、様々なタイプのリクエストを処理し、適切なリクエストハンドラーにディスパッチする機能をサポートしています。リクエストハンドラーはIRequestHandlerインターフェースを実装し、特定のリクエストタイプを受け取り、対応する処理ロジックを実行します。
- リクエスト: リクエストとは、アプリケーションに対して特定の操作を実行するコマンドまたはクエリです。MediatRでは、リクエストはIRequestインターフェースによって定義され、戻り値(IRequest<TResponse>)を持つか、または戻り値を持たないかのいずれかになります。
- 通知処理:MediaTekは、リクエストに加えて、通知の発行と適切な通知ハンドラーへの配信もサポートしています。通知ハンドラーはINotificationHandlerインターフェースを実装し、特定の種類の通知を受信し、対応する処理ロジックを実行します。
- 通知: 通知は、アプリケーションの他の部分にメッセージをブロードキャストするオブジェクトです。リクエストとは異なり、通知は結果を返す必要はなく、対応する通知ハンドラーが適切なアクションを実行するだけで済みます。
MediatR を使用すると、開発者はアプリケーション内のロジックをより適切に整理および分離し、要求と通知の処理ロジックを別々のハンドラーに集中させることができるため、コードの保守性とテスト可能性が向上します。 リクエストと処理MediaTekでは、リクエストと処理は、リクエスト・レスポンス・メッセージ通信を実装するための中核概念です。主なコンポーネントは次のとおりです。 - リクエストとは、アプリケーションに指示を送信したり、特定のデータを取得したりするために用いられるコマンドまたはクエリです。MediaTekでは、リクエストは戻り値(IRequest<TResponse>)を持つ場合と、戻り値を持たない場合があります。リクエストオブジェクトは、対応するリクエストインターフェースを実装し、必要なプロパティとメソッドを定義する必要があります。
- リクエスト処理:リクエスト処理とは、リクエストを処理するプロセスを指します。MediaTekでは、リクエストハンドラーは `IRequestHandler<TRequest, TResponse>` インターフェースを実装し、特定のタイプのリクエストを受信し、対応する論理演算を実行します。リクエストハンドラーは、インターフェースに `Handle()` メソッドを実装することでリクエストを処理し、対応する結果(存在する場合)を返します。
- リクエストの送信:MediatR を使用してリクエストを送信する際は、Mediator の Send() メソッドを使用して、リクエストを適切なリクエストハンドラに送信できます。Send() メソッドは適切なリクエストハンドラを検索し、リクエストをハンドラに渡して処理させます。リクエストに戻り値がある場合、Send() メソッドは処理された結果を返します。
- 非同期リクエスト処理:MediaTekは非同期リクエスト処理をサポートしています。これは、リクエスト処理メソッドの非同期バージョンを実装することで実現できます。非同期リクエストハンドラーは、リクエストを非同期に処理するために、`Task<TResponse> HandleAsync(TRequest request, CancellationToken cancellationToken)` メソッドを実装する必要があります。
MediatR のリクエストおよび処理パターンを使用すると、リクエストと処理ロジックの分離、コードの保守性とテスト性の向上、制御フローの簡素化など、多くのメリットが得られます。Mediator パターンを使用することで、リクエストと処理間の依存関係はメディエーターに限定され、システムの柔軟性とスケーラビリティが向上します。 通知と処理MediaTekでは、通知と処理はパブリッシュ・サブスクライブ型メッセージングを実装するためのもう一つのコアコンセプトです。主なコンポーネントは以下のとおりです。 - 通知:通知は、アプリケーションの他の部分に情報をブロードキャストするために使用されるメッセージです。通知は結果を返す必要はなく、対応する通知ハンドラーが適切なアクションを実行するだけで済みます。MediaTekでは、通知オブジェクトは特定のインターフェース要件を持たないシンプルなクラスであり、必要なプロパティとメソッドのみを定義する必要があります。
- 通知処理:通知処理とは、通知を処理するプロセスを指します。MediaTekでは、通知ハンドラーは `INotificationHandler<TNotification>` インターフェースを実装し、特定の種類の通知を受信し、対応する論理演算を実行します。通知ハンドラーは、インターフェースに `Handle()` メソッドを実装することで通知を処理します。
- 通知のパブリッシュ:MediatRを使用して通知をパブリッシュする場合、MediatorのPublish()メソッドを使用して、対応するすべての通知ハンドラーに通知をパブリッシュできます。Publish()メソッドは、一致する通知ハンドラーを検索し、通知をそれらのハンドラーに渡して処理させます。リクエストとは異なり、通知は結果を返す必要はありません。
- 非同期通知処理:MediaTekは非同期通知処理もサポートしており、これは通知処理メソッドの非同期バージョンを実装することで実現できます。非同期通知ハンドラーは、非同期通知処理のために`Task Handle(TNotification notification, CancellationToken cancellationToken)`メソッドを実装する必要があります。
MediaTekの通知および処理パターンを使用することで、疎結合なメッセージ通信が可能になり、パブリッシャーとサブスクライバーが分離され、優れたスケーラビリティと保守性が実現します。通知を発行することで、アプリケーションのさまざまな部分が特定のイベントに関する情報をリアルタイムで受信し、対応するアクションを実行できます。このパターンはイベント駆動型システムで非常に有用であり、システムの設計と開発プロセスを簡素化します。 パイプライン処理パイプMediaTekにおける処理パイプラインとは、リクエスト/通知をインターセプトして処理するためのメカニズムです。これにより、リクエスト/通知がハンドラーに到達する前または後に、一連の中間操作を実行できます。主なコンポーネントは以下のとおりです。 - 処理パイプライン:処理パイプラインは、リクエスト/通知がハンドラーに到着する前後に事前定義された操作を実行するミドルウェアのチェーンです。各ミドルウェアは、リクエスト/通知を変更したり、ロジックを追加したり、その他の関連タスクを実行したりできます。
- リクエストパイプライン:リクエストパイプラインはリクエスト処理パターンで使用され、リクエストオブジェクトが通過する処理パスです。リクエストパイプライン内のミドルウェアは、リクエストが最終リクエストハンドラに到達するまで順次実行されます。各ミドルウェアは、リクエストがハンドラに到達する前または後に、検証、ログ記録、例外処理などの特定のロジックを実行できます。
- 通知パイプライン:通知パイプラインは通知処理パターンに適用され、通知オブジェクトが通過する処理パスです。通知パイプライン内のミドルウェアは、通知が対応するすべての通知ハンドラーに到達するまで順次実行されます。各ミドルウェアは、通知がハンドラーに到達する前または後に、ログ記録や他のシステムへの通知送信など、特定のロジックを実行できます。
- グローバルパイプライン:MediatRは、すべてのリクエストと通知に適用される汎用的な処理パイプラインであるグローバルパイプラインも提供します。グローバルパイプライン内のミドルウェアは、リクエスト/通知ごとにリクエストパイプラインまたは通知パイプラインの前または後に実行され、セキュリティ認証、パフォーマンストレースなどのグローバルレベルの処理ロジックを提供します。
処理パイプラインを構成することで、必要に応じてリクエストや通知をインターセプトし、変更することで、ログ記録、検証、キャッシュ、エラー処理といった様々な機能を実現できます。MediatRが提供する拡張ポイントを使用して、処理パイプライン内にミドルウェアを登録・構成することで、定義された操作を順次実行できます。これにより、コードの再利用性、スケーラビリティ、保守性が向上し、特定のビジネス要件に合わせて処理パイプラインをカスタマイズできるようになります。 リクエストの前処理MediaTekにおけるリクエスト前処理とは、リクエストが対応するハンドラーに到達する前に実行される一連の操作を指します。これにより、リクエストの検証、リクエスト内容の変更、ログ記録など、実際のリクエストが処理される前に必要な処理を実行できます。主なコンポーネントは次のとおりです。 - リクエストプリプロセッサ:リクエストプリプロセッサは、リクエストがハンドラに到達する前に特定の操作を実行するために使用されるミドルウェアです。`IPipelineBehavior<TRequest, TResponse>`インターフェースを実装し、`Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)`メソッドを実装することでリクエストを処理します。リクエストプリプロセッサは、リクエストオブジェクトを次のハンドラに渡す前に、検査、検証、変更、またはログに記録することができます。
- グローバルリクエストプリプロセッサ:MediaTRは、すべてのリクエストに適用される汎用プリプロセッサであるグローバルリクエストプリプロセッサも提供します。グローバルリクエストプリプロセッサはIPipelineBehavior<TRequest, TResponse>インターフェースを実装し、登録および設定時にすべてのリクエストに適用します。グローバルリクエストプリプロセッサは、リクエストパイプライン内で各リクエストに対して実行され、グローバルレベルの処理ロジックを提供します。
リクエストプリプロセッサを使用すると、リクエストの検証、認証、データ変換、例外処理など、実際のリクエストが処理される前に様々な操作を実行できます。これにより、リクエスト関連の共通タスクを一元化し、リクエストハンドラを実際のビジネスロジックに集中させることができます。アプリケーションの設定でリクエストプリプロセッサを登録および設定すると、MediaTek は対応するリクエストに自動的に適用します。 リクエストプリプロセッサはオプションであり、その使用はニーズとアプリケーション設計によって異なります。特定のビジネス要件に合わせて、リクエストプリプロセッサを選択的に追加、設定、使用することができます。 例外処理MediaTekでは、例外ハンドラを使用して、リクエストまたは通知の処理中に発生する例外を処理できます。例外ハンドラを使用すると、例外をキャッチして処理し、ログ記録、アラートの送信、特定のエラー応答の返送など、適切なアクションを実行できます。主な機能は次のとおりです。 - 例外ハンドラー:例外ハンドラーは、リクエストまたは通知の処理中に例外を捕捉して処理するために使用されるミドルウェアです。`IExceptionAction<TRequest, TResponse, TException>`インターフェースを実装し、`Task<TResponse> Handle(TRequest request, TException exception, CancellationToken cancellationToken, ExceptionHandlerDelegate<TResponse> next)`メソッドを実装することで例外を処理します。例外ハンドラーは、ログ記録、アラートの送信、エラー応答の返送など、特定の例外の種類に基づいて適切なアクションを実行できます。
- グローバル例外ハンドラー:MediaTekは、すべてのリクエストと通知に適用される汎用的な例外ハンドラーであるグローバル例外ハンドラーも提供しています。グローバル例外ハンドラーは、`IExceptionAction<TRequest, TResponse, TException>`インターフェースを実装し、登録および設定時にすべてのリクエストと通知に適用します。グローバル例外ハンドラーは、各リクエストと通知の処理中に例外を捕捉して処理することで、統一された例外処理ロジックを提供します。
例外ハンドラを使用すると、リクエストまたは通知の処理中に例外を捕捉して処理することで、アプリケーションの安定性と信頼性を確保できます。トラブルシューティングのためのログ記録、タイムリーな問題解決のためのアラート送信、クライアントへの通知のための特定のエラー応答の返送など、特定の例外の種類に基づいて適切なアクションを実行できます。また、例外ハンドラは例外処理を柔軟にカスタマイズできるため、必要に応じて異なる例外処理ロジックを定義できます。 例外ハンドラはオプションであり、その使用はニーズとアプリケーション設計によって異なります。特定のビジネス要件を満たすために、例外ハンドラを選択的に追加、設定、使用することで、プロセス中に潜在的な例外が適切に処理されることを保証できます。 メディエーターのライフサイクルMediatRでは、メディエーターのライフサイクルはコンテナによって管理されます。具体的なライフサイクルは、選択したコンテナの種類によって異なります。一般的なコンテナとしては、ASP.NET Core、Autofac、SimpleInjectorなどがあります。 ASP.NET Coreでは、デフォルトでメディエーターのライフサイクルはリクエストのライフサイクルと同期されます。つまり、リクエストごとに新しいメディエーターインスタンスが作成され、リクエスト処理中に使用されます。この短いライフサイクルにより、各リクエストに専用のメディエーターインスタンスが割り当てられ、リクエスト間の干渉や状態共有の問題を回避できます。リクエストが完了すると、メディエーターインスタンスは破棄されます。 他のコンテナを使用する場合、ニーズに応じてメディエーターのライフサイクルを設定できます。例えば、Autofacコンテナでは、登録型のライフサイクルオプションを設定することで、メディエーターのライフサイクルを制御できます。一般的なライフサイクルオプションには、Transient、Scoped、Singletonがあります。Transientライフサイクルでは、解決リクエストごとに新しいメディエーターインスタンスが作成され、Scopedライフサイクルでは各スコープ内で同じメディエーターインスタンスが共有され、Singletonライフサイクルでは、アプリケーションライフサイクル全体を通じて同じメディエーターインスタンスが共有されます。 シングルトンのライフサイクル中はメディエーターインスタンスが共有されるため、状態共有の問題が発生する可能性があることに注意することが重要です。したがって、メディエーターを設計する際には、各リクエストの独立性と再現性を確保するために、メディエーターインスタンスの状態に依存したり変更したりしないようにする必要があります。 まとめると、MediatRメディエーターのライフサイクルは、使用するコンテナの種類と構成によって異なります。ASP.NET Coreでは、メディエーターのライフサイクルはリクエストのライフサイクルと同期されますが、他のコンテナでは必要に応じて構成できます。使用するライフサイクルに関わらず、各リクエストの独立性と信頼性を確保するため、メディエーターインスタンス間での状態共有の問題を回避するよう注意する必要があります。 MediatR 適用可能なシナリオMediatRは、メディエーターパターンを実装するためのライブラリです。リクエストと通知の処理を分離し、様々なシナリオに適した方法を提供します。MediatRが適用可能なシナリオをいくつかご紹介します。 - CQRS(コマンド・クエリ責務分離):MediatRは、CQRSアーキテクチャにおけるコマンドとクエリの分離を実装するために使用できます。コマンドとクエリを異なるリクエストオブジェクトにカプセル化し、メディエーターパターンを使用してこれらのリクエストを処理することで、複雑なビジネスロジックをより適切に整理・管理できます。
- イベント駆動型アーキテクチャ:MediatRは、イベントのパブリッシュおよびサブスクリプションパターンを実装するために使用できます。イベント通知を定義および処理することで、疎結合なコンポーネント間通信、より柔軟なシステム拡張、非同期処理を実現できます。
- プラグ可能で拡張可能:MediatRは、プラグ可能で拡張可能なアプリケーションアーキテクチャを実装するために使用できます。共通のリクエストおよび処理ロジックを定義し、メディエーターパターンを使用してリクエストと処理を分離することで、さまざまな機能モジュールを簡単に追加、削除、置換できます。
- ビューモデルの更新:MediatRはビューモデルの更新操作を処理できます。更新リクエストと対応するハンドラーを定義することで、ビューモデルの追加、削除、変更などの操作を実装し、更新完了後に適切なタイミングでインターフェースを更新するよう関連コンポーネントに通知できます。
- ドメインイベントとコマンド:MediatRはドメインイベントとコマンドの処理に使用できます。対応するイベントとコマンドを定義し、メディエーターパターンを用いて処理することで、ドメインロジックを効果的に整理・管理し、分離され、テスト可能でスケーラブルなドメインモデルを実現できます。
全体として、MediatRはリクエストと処理ロジックの分離を必要とするシナリオに適しており、コードの可読性、保守性、スケーラビリティを向上させます。他のアーキテクチャパターン(CQRS、イベントドリブンアーキテクチャなど)と組み合わせて使用することで、さまざまなビジネスニーズやシステム設計要件に対応できます。 MediatRのメリットとデメリットMediatR は、次のような利点と欠点を持つ強力なメディエーター パターン ライブラリです。 アドバンテージ: - 分離と組織化:MediatRは、Mediatorパターンを用いてリクエストと処理ロジックを整理します。この分離により、コードのモジュール化、可読性、テストおよび保守性が向上します。
- 柔軟性と拡張性:MediatRは、様々なプロセッサの追加、削除、交換を容易にする柔軟なアーキテクチャを提供します。これにより、アプリケーションのスケーラビリティが向上し、ビジネスニーズに基づいたカスタマイズされた開発が可能になります。
- 再利用性の向上:リクエストと処理を分離することで、MediaTRはコードの再利用性を高めます。同じリクエストを異なるハンドラーで使用できるほか、ハンドラーを変更したり置き換えたりしても他の部分に影響を与えません。
- 複数のアーキテクチャ パターンに適用可能: MediatR は、さまざまなビジネス ニーズやシステム設計要件を満たすために、さまざまなアーキテクチャ パターン (CQRS、イベント駆動型アーキテクチャなど) と組み合わせて使用できます。
欠点: - 複雑さの増大:MediatR の使用は、ある程度の複雑さをもたらします。リクエスト/プロセッサの設定と定義には追加の作業が必要となり、開発と保守の作業負荷が増加する可能性があります。さらに、MediatR を正しく使用することが重要です。そうでないと、仲介者やプロセッサが多すぎると、理解しにくく保守が困難なコードになる可能性があります。
- パフォーマンスのオーバーヘッド:MediatRはメディエーターパターンを使用し、リクエストとプロセッサ間のメッセージをこのメディエーターを介して中継する必要があるため、パフォーマンスのオーバーヘッドが発生する可能性があります。大規模かつ高同時実行性のアプリケーションでは、パフォーマンスの最適化とチューニングが必要になる場合があります。
- 学習曲線:MediatRは強力なライブラリですが、その概念、API、ベストプラクティスを理解するには、ある程度の学習が必要です。チームメンバーは、MediatRの使用方法と設計原則を習得し、理解するために時間と労力を費やす必要があります。
全体的に見ると、MediatR の利点は欠点をはるかに上回っていますが、プロジェクト要件とテクノロジ スタックが MediatR に適しているかどうか、また複雑さとパフォーマンスのオーバーヘッドの増加がその利点を得るための価値があるかどうかを判断するために、MediatR を使用する前に慎重に検討する必要があります。 MediatRの事例以下は、MediatR を使用した ASP.NET Core の例で、複数のリクエストを処理し、アプリケーションでパイプラインを使用する方法を示しています。 まず、MediatRと関連するNuGetパッケージがプロジェクトにインストールされていることを確認してください。以下のコマンドでインストールできます。 dotnet add package MediatR dotnet add package MediatR.Extensions.Microsoft.DependencyInjection 次に、Startup.cs ファイルを開き、次のコードを ConfigureServices メソッドに追加して、MediatR と関連する依存関係の挿入を構成します。 上記のコードでは、AddMediatRメソッドを使用してMediatRをDIコンテナに登録しています。これは、以下のコードを渡すことで実行されます。 Assembly.GetExecutingAssembly() は、現在のアセンブリ内のすべての要求とハンドラーをスキャンします。 次に、複数のリクエストの処理を示すために、いくつかのリクエストとハンドラーを作成します。 まず、単純なリクエスト HelloWorldRequest とそれに対応するハンドラー HelloWorldHandler を作成します。 using MediatR; using System.Threading; using System.Threading.Tasks; public class HelloWorldRequest : IRequest<string> { // 请求的属性和数据// ... } public class HelloWorldHandler : IRequestHandler<HelloWorldRequest, string> { public Task<string> Handle(HelloWorldRequest request, CancellationToken cancellationToken) { // 处理请求并返回结果string result = "Hello, World!"; return Task.FromResult(result); } } 次に、別のリクエスト GreetUserRequest と、それに対応するハンドラー GreetUserHandler を作成します。 using MediatR; using System.Threading; using System.Threading.Tasks; public class GreetUserRequest : IRequest<string> { public string UserName { get; set; } } public class GreetUserHandler : IRequestHandler<GreetUserRequest, string> { public Task<string> Handle(GreetUserRequest request, CancellationToken cancellationToken) { // 处理请求并返回结果string result = $"Hello, {request.UserName}!"; return Task.FromResult(result); } } 上記のコードでは、GreetUserRequest は UserName プロパティを持つ要求クラスであり、GreetUserHandler は GreetUserRequest 要求を処理するハンドラーです。 次に、コントローラーで MediatR を使用して、複数のリクエストとハンドラーを組み合わせます。 using MediatR; using Microsoft.AspNetCore.Mvc; using System.Threading.Tasks; [ApiController] public class HelloWorldController : ControllerBase { private readonly IMediator _mediator; public HelloWorldController(IMediator mediator) { _mediator = mediator; } [HttpGet("/hello")] public async Task<IActionResult> SayHello() { var helloRequest = new HelloWorldRequest(); var greetUserRequest = new GreetUserRequest { UserName = "John" }; // 使用MediatR 发送多个请求并获取结果string helloResult = await _mediator.Send(helloRequest); string greetUserResult = await _mediator.Send(greetUserRequest); return Ok(new { Hello = helloResult, GreetUser = greetUserResult }); } } 上記のコードでは、SayHelloメソッド内でHelloWorldRequestとGreetUserRequestを作成し、MediatRの_mediatorオブジェクトを使用してこれら2つのリクエストを送信し、結果を取得しました。最後に、結果をクライアントに返しました。 この例では、MediatR を使用して複数のリクエストとハンドラーを処理する方法と、それらをコントローラーで組み合わせる方法を示します。 アプリケーションの複雑さや要件に応じて、パイプラインを使用してリクエストの検証、例外処理、ログ記録など、さまざまな機能を実装することもできます。MediatRは、ニーズに合わせて処理手順をカスタマイズするための豊富な拡張ポイントを提供しています。 |