同期操作と非同期操作
ローカルでの非同期実装と非同期呼び出し、および非同期メッセージ交換の同期使用について説明します。
多くのアプリケーションは、メソッド呼び出しの実行中に有用な処理を続行できるように、メソッドを非同期に呼び出します。Windows Communication Foundation (WCF) サービスおよびクライアントは、アプリケーションの 2 つの異なるレベルで操作の非同期呼び出しに参加できます。これにより、WCF アプリケーションの柔軟性がさらに高まり、対話機能とのバランスの取れた最適なスループットが実現します。
非同期操作の種類
WCF のすべてのサービス コントラクトでは、パラメーターの型や戻り値に関係なく、WCF の属性を使用してクライアントとサービス間の特定のメッセージ交換パターンを指定します。WCF は、適切なサービス操作または実行元のクライアント コードに送受信メッセージを自動的にルーティングします。
クライアントが所有するのは、特定操作のメッセージ交換パターンが指定されたサービス コントラクトのみです。基盤となるメッセージ交換パターンに従っている限り、クライアントは選択する任意のプログラミング モデルを開発者に提供できます。同様に、サービスも、指定されたメッセージ パターンに従っている限り、任意の方法で操作を実装できます。
サービス コントラクトがサービスとクライアントの両方の実装から独立していることで、WCF アプリケーションでは次の形式の非同期実行が可能になります。
クライアントは、同期メッセージ交換を使用して要求/応答操作を非同期に呼び出すことができます。
サービスは、同期メッセージ交換を使用して要求/応答操作を非同期に実装できます。
クライアントまたはサービスの実装に関係なく、一方向のメッセージ交換が可能です。
推奨される非同期シナリオ
操作のサービス実装でブロッキング呼び出し (I/O 処理の実行など) を作成する場合は、サービス操作の実装で非同期手法を使用します。非同期操作を実装している場合、非同期の操作とメソッドを呼び出して、できるだけ非同期呼び出しパスを拡張するようにします。たとえば、BeginOperationOne()
内から BeginOperationTwo()
を呼び出します。
次のような場合には、クライアントまたは呼び出し元アプリケーションで非同期手法を使用します。
中間層アプリケーションから操作を呼び出す場合 (このようなシナリオ詳細情報、「中間層クライアント アプリケーション」を参照してください)。
ASP.NET ページ内で操作を呼び出す場合、非同期ページを使用します。
シングル スレッドのアプリケーション (Windows フォームや Windows Presentation Foundation (WPF) など) から操作を呼び出す場合。イベント ベースの非同期呼び出しモデルを使用すると、結果イベントが UI スレッドで発生するので複数のスレッドを独自に処理する必要がなく、アプリケーションの応答性が向上します。
一般に、同期呼び出しと非同期呼び出しのいずれかを選択する場合は、非同期呼び出しを選択します。
クライアント側の非同期呼び出し
WCF クライアント アプリケーションでは、「Asynchronous Programming Design Patterns」に記載された次の 2 つの非同期呼び出しモデルのいずれかを使用できます。
イベントを使用する非同期操作
System.IAsyncResult オブジェクトを使用する非同期操作
1 つ目のイベント ベースの非同期パターンでは、応答の通知を受信するイベント ハンドラーを追加するだけで済み、結果イベントはユーザー インターフェイス スレッドで自動的に発生するため、呼び出し元アプリケーションにはこの手法をお勧めします。この手法を使用するには、次の例に示すように、ServiceModel メタデータ ユーティリティ ツール (Svcutil.exe) で /async と /tcv:Version35 の両方のコマンド オプションを指定します。
svcutil https://localhost:8000/servicemodelsamples/service/mex /async /tcv:Version35
これらのオプションを指定すると、Svcutil.exe によって、イベント インフラストラクチャを持つ WCF クライアント クラスが生成されます。このインフラストラクチャにより、呼び出し元アプリケーションは、応答を受信して適切なアクションを実行するイベント ハンドラーを実装し、割り当てることができます。詳細な例については、「方法 : WCF サービス操作を非同期に呼び出す」を参照してください。
イベント ベースの非同期モデルは、.NET Framework Version 3.5 でのみ使用できます。また、System.ServiceModel.ChannelFactory を使用して WCF クライアント チャネルを作成した場合は、.NET Framework 3.5 でもサポートされません。WCF クライアント チャネル オブジェクトを使用する場合、System.IAsyncResult オブジェクトを使用して操作を非同期に呼び出す必要があります。この手法を使用するには、次の例に示すように、ServiceModel メタデータ ユーティリティ ツール (Svcutil.exe) で /async コマンド オプションを指定します。
svcutil https://localhost:8000/servicemodelsamples/service/mex /async
これにより、対応する <End> メソッドを持ち、AsyncPattern プロパティが true に設定された <Begin> メソッドとして各操作がモデル化されたサービス コントラクトが生成されます。ChannelFactory の詳細な使用例については、「方法 : チャネル ファクトリを使用して、非同期的に操作を呼び出す」を参照してください。
いずれの場合も、サービスが同期的に実装されていても、アプリケーションは操作を非同期に呼び出すことができます。これは、アプリケーションで同じパターンを使用してローカルの同期メソッドを非同期に呼び出す場合と同様です。クライアントにとって操作がどのように実装されているかは重要ではありません。応答メッセージが到着すると、その内容がクライアントの非同期 <End> メソッドにディスパッチされ、クライアントは情報を取得します。
非同期操作の実装
同様に、.NET Framework 非同期プログラミング パターンを使用し、AsyncPattern プロパティを true に設定した <Begin> メソッドを使用することで、サービス操作を非同期に実装できます。この場合の非同期操作は、同期操作と同じ形式でメタデータに公開されます。つまり、要求メッセージとそれに関連する応答メッセージを伴う単独操作として公開されます。このとき、クライアント プログラミング モデルは選択が可能です。サービスが呼び出されたときに要求/応答メッセージ交換が行われていれば、クライアント プログラミング モデルは、このパターンを同期操作または非同期操作として表すことができます。
一般に、システムの非同期の性質を考えると、スレッドへの依存は避ける必要があります。操作のディスパッチ処理のさまざまな段階にデータを渡す最も信頼性の高い方法は、拡張機能を使用する方法です。
例については、「方法 : 非同期サービス操作を実装する」を参照してください。
クライアント アプリケーションでの呼び出し方法に関係なく、非同期に実行するコントラクト操作 X
を定義するには次の処理を実行します。
パターン BeginOperation と EndOperation を使用する 2 つのメソッドを定義します。
BeginOperation メソッドには操作のための in パラメーターと ref パラメーターがあり、IAsyncResult 型を返します。
EndOperation メソッドには IAsyncResult パラメーター、out パラメーター、および ref パラメーターがあり、操作の戻り値の型を返します。
たとえば、次のメソッドを参照してください。
int DoWork(string data, ref string inout, out string outonly)
Function DoWork(ByVal data As String, ByRef inout As String, _
out outonly As out) As Integer
非同期操作を作成するには、2 つのメソッドを次のように記述します。
[OperationContract(AsyncPattern=true)]
IAsyncResult BeginDoWork(string data,
ref string inout,
AsyncCallback callback,
object state);
int EndDoWork(ref string inout, out string outonly, IAsyncResult result);
<OperationContract(AsyncPattern := True)> _
Function BeginDoWork(ByVal data As String, _
ByRef inout As String, _
ByVal callback As AsyncCallback, _
ByVal state As Object) _
As IAsyncResult
Function EndDoWork(ByRef inout As String, _
ByRef outonly As String, _
ByVal result As IAsyncResult) _
As Integer
注 : |
---|
OperationContractAttribute 属性は、BeginDoWork のメソッドにのみ適用されます。生成されるコントラクトには、DoWork という名前の WSDL 操作が 1 つ含まれます。
|
一方向メッセージ交換パターン
クライアントまたはサービスが単独で一方向操作 (System.ServiceModel.OperationContractAttribute.IsOneWay が true に設定されている操作には相関する応答がない) を相手側に送信できる、非同期メッセージ交換パターンを作成することもできます (双方向メッセージ交換パターンを一方向メッセージで使用します)。この場合、サービス コントラクトは、両側が非同期呼び出しまたは非同期実装として実装できる一方向メッセージ交換を指定します。また、状況によっては指定しません。一般的に、コントラクトが一方向メッセージ交換の場合、メッセージが送信されるとアプリケーションは応答を待機することなく他の作業を継続できるため、多くの場合、実装が同期的になります。
イベント ベースの非同期クライアントとメッセージ コントラクト
イベント ベースの非同期モデルのデザイン ガイドラインには、複数の値を返す場合に、1 つの値を Result プロパティとして返し、残りの値を EventArgs オブジェクトのプロパティとして返すことが記載されています。この 1 つの結果として、クライアントがイベント ベースの非同期コマンド オプションを使用してメタデータをインポートし、操作から複数の値が返される場合、既定の EventArgs オブジェクトは 1 つの値を Result プロパティとして返し、残りの値は EventArgs オブジェクトのプロパティになります。
メッセージ オブジェクトを Result プロパティとして受け取り、返された値をそのオブジェクトのプロパティとして取得する場合は、/messageContract コマンド オプションを使用します。これにより、EventArgs オブジェクトの Result プロパティとして応答メッセージを返すシグネチャが生成されます。すべての内部戻り値は、応答メッセージ オブジェクトのプロパティになります。