非同期コントローラー(AsyncController)
MVC 2では、通常のコントローラーの他に、非同期コントローラーが追加されています。非同期コントローラーとはどのようなものなのかを見てみましょう。
Controllerとの違い
通常のコントローラー(同期コントローラー)と非同期コントローラーの違いは、その名のとおり、アクションメソッドに対して同期を取るか、非同期で処理が実行されるかの違いです。
使用するシナリオとして例えば、クロスドメインでのアクセスとなるWebサービスにアクセスする時、または要求処理に時間がかかるロジックが記載されている時など、時間がかかるネットワークI/O周りで活躍します。
物理的な違いとしてXXXController.csファイル内に記載されているコントローラークラスの継承元がControllerもしくは、AsyncControllerという違いもあります。非同期コントローラーを利用する場合は、AsyncControllerに記述を変更します。その他にも非同期コントローラーには利用時の命名規則があります。
命名規則とアクションメソッドの制限
非同期コントローラー内で非同期処理をする場合、同期コントローラーで記載しているメソッドを分割し、「起動」と「完了」メソッド2つ用意します。起動と完了メソッドは事前の設定は不要ですが、メソッド名にそれぞれ固定のキーワードを入れなければ動作しません。
処理 | メソッドの命名規則 |
起動時 | XXXXAsync(Asyncを最後に記載) |
完了時 | XXXXCompleted(Completedを最後に記載) |
他にもアクションメソッド(非同期でないものも含む)でいくつか制限があります。
- publicのみサポート(privateなどでは動作しない)
- 静的メソッドにもサポートしない
- 原則パラメタを使用したオーバーロードはできない
- アクションメソッドではないことを示すNonActionAttribute属性や、Postリクエストのみ処理を実行するHttpPostAttribute属性を使用し、厳密化させることでオーバーロードできる
癖が強い部分ですが、使用する中ですぐに身に付く部分でもあります。
AsyncControllerを使用する上で抑えるべきクラス
続いて、AsyncControllerを使用する際の主要なクラスを紹介します。押さえるべき主要クラスは以下の2つです。
クラス名 | 概要 |
AsyncController | 非同期処理の開始・終了に関する機能を内包 |
AsyncManager | AsyncControllerクラスの非同期処理の操作を管理 |
名前のとおり、非同期処理を実行するクラスと管理するクラスです。
AsyncControllerを使用する
それでは、実際にサンプルを作成してみましょう。今回は利用方法を学習するためのサンプルなので、Webサービスは利用せずに、Thread.Sleepメソッドを使用します。実行結果は図1~2になります。
さっそくコントローラー側の処理を見てみましょう。
// (1) // 起動メソッド名はXXXXAsync public void SampleAsync() { // 残りの操作数をインクリメント AsyncManager.OutstandingOperations.Increment(); // Webサービスを利用する場合はインクリメント後にイベント登録や処理を記述 Thread.Sleep(3000); // 完了メソッドに渡すパラメタ AsyncManager.Parameters["pic"] = "/Content/Tamaki.png"; // 残りの操作数をデクリメント AsyncManager.OutstandingOperations.Decrement(); } // (2) // 完了メソッド名はXXXXCompleted public ActionResult SampleCompleted(string pic) { return File(pic,"image/png"); }
今回は、同期コントローラーでSampleアクションメソッドと記述する部分を非同期コントローラーに対応させています。
順に説明します。
(1)起動メソッドの命名規則に沿い、SampleAsyncメソッドを作成しています(アクションメソッド型などの指定もできますが、非同期処理終了時に完了メソッドを呼び出すため、voidで記述しています)。
メソッド内部では、AsyncManagerクラスの制御がポイントです。コード内に記載されているAsyncManagerプロパティはAsyncManagerのインスタンスを取得します。
OutstandingOperationsプロパティは非同期処理の保留中の操作数を管理しています。起動メソッドでは、最初にOutstandingOperationsプロパティをIncrementメソッドでインクリメントします。逆に、カウンタを減らすにはDecrementメソッドでデクリメントします。
Parametersプロパティは、起動メソッドから、完了メソッドにパラメタ渡しを行うために用意されています。IDictionaryインターフェイスを実装しているため、渡したい値はキーバリュー型で設定します(サンプルでは画像のURL)。
以上が起動メソッドのポイントです。必要に応じて繰り返し処理なども簡単に記述できることがご確認いただけたかと思います。続いて完了メソッドです。
(2)完了メソッドの命名規則に沿い、SampleCompletedアクションメソッドを作成しています。なお、パラメタには、起動メソッド内で設定されたParametersプロパティの値を記載できます。
必要な処理を記載し、最後にViewなどを戻り値として設定するだけです。XXXXAsyncメソッドに比べると同期メソッドのような記述に近くなります。サンプルでは、Fileメソッドを使用し、画像を表示しています。Fileメソッドは第一パラメタにファイル本体またはパスを、第二パラメタにコンテンツタイプを指定することで利用できます。
実行結果は図1~2のとおりです。
以上が、非同期コントローラーの基本的な使用方法です。Webサービスを利用する場合の処理はサンプル(HomeController.csとAsyncCalc.aspx)を参照ください。
非同期コントローラーは考え方や、使用箇所、ロジックの複雑化など一定のハードルがあります。逆にこれらをしっかりと見極めて使用する際には効果的なコントローラーでもあります。最後に同期コントローラーと、非同期コントローラーの使いどころとデメリットについてまとめます。
コントローラー | 使いどころ | デメリット |
同期コントローラー | ASP.NET MVCにおける開発全般で使用。基本的には同期コントローラーで十分。 | ネットワークI/Oの負荷が高い処理やスレッドプールを占有してしまいそうな処理を実行する際に遅延が発生してしまう。 |
非同期コントローラー | ネットワークI/Oの負荷が高い処理や、スレッドプールを一時的に非同期で処理を実行したい時、複数のWebサービスにまとめてリクエストをする際に使用。 | 同期コントローラーに比べてオーバーヘッドがある。処理が複雑化する。 |
新機能の登場により、そちらを利用しよう、という流れになりがちですが、同期コントローラーと非同期コントローラーは明確な棲み分けがあります。繰り返しになりますが、基本的には同期コントローラーを使用し、パフォーマンス上、ネットワークI/Oなどがネックになる場合のみ非同期コントローラーを利用するようにしましょう。
必要なシナリオでは非同期コントローラーをどんどん活用してください。