メッセージ交換パターンの選択

カスタム トランスポートを作成する最初の手順は、開発するチャネルに必要な メッセージ交換パターン (または MEP) を決定することです。 このトピックでは、使用可能なオプションについて説明し、さまざまな要件について説明します。 これは、「チャネルの開発」で説明されているチャネル開発タスクリストの最初のタスク です。

6 つのメッセージ交換パターン

次の 3 つの MEP から選択できます。

  • データグラム (IInputChannel と IOutputChannel)

    データグラム MEP を使用する場合、クライアントは ファイアアンドフォーゲット 交換を使用してメッセージを送信します。 このような交換では、配信の成否について帯域外での確認が必要になります。 メッセージが転送中に失われ、サービスに到達しない可能性があります。 クライアント側で送信操作が正常に完了した場合、リモート エンドポイントがメッセージを受信したという保証はありません。 データグラムは、信頼性の高いプロトコルやセキュリティで保護されたプロトコルなど、独自のプロトコルをその上に構築できるため、メッセージングの基本的な構成要素です。 クライアント データグラム チャネルは IOutputChannel インターフェイスを実装し、サービス データグラム チャネルは IInputChannel インターフェイスを実装します。

  • Request-Response (IRequestChannel と IReplyChannel)

    この MEP では、メッセージが送信され、応答が受信されます。 このパターンは、要求と応答のペアで構成されます。 要求応答呼び出しの例としては、リモート プロシージャ コール (RPC) とブラウザーの GET 要求があります。 このパターンは半二重とも呼ばれます。 この MEP では、クライアント チャネルは IRequestChannel を実装し、サービス チャネルは IReplyChannelを実装します。

  • 二重 (IDuplexChannel)

    双方向 MEP を使用すると、任意の数のメッセージをクライアントから送信し、任意の順序で受信できます。 双方向 MEP は電話での会話のようなもので、話されている各単語はメッセージです。 この MEP では両方の側が送受信できるため、クライアント チャネルとサービス チャネルによって実装されるインターフェイスは IDuplexChannel。

3 つの基本的なメッセージ交換パターンを示すフローチャート 3 つの基本的なメッセージ交換パターン。 上から下へ: データグラム、要求応答、二重。

これらの各 MEP は セッションをサポートすることもできます。 セッション (および System.ServiceModel.Channels.ISessionChannel<TSession> 型のSystem.ServiceModel.Channels.ISessionの実装) は、チャネルで送受信されるすべてのメッセージを関連付けます。 要求と応答のパターンは、要求と応答が関連付けられるスタンドアロンの 2 メッセージ セッションです。 これに対し、セッションをサポートする要求/応答パターンは、そのチャネル上のすべての要求と応答のペアが相互に関連付けられることを意味します。 これにより、合計 6 つの MEP から選択できます。

  • データグラム

  • リクエスト-レスポンス

  • Duplex

  • セッションを含むデータグラム

  • セッション対応要求 – 応答

  • セッション対応二重

注

UDP トランスポートでは、UDP は本質的にファイア アンド フォーゲット プロトコルであるため、サポートされている MEP はデータグラムのみです。

セッションとセッションの多いチャネル

ネットワークの世界には、接続指向プロトコル (TCP など) と接続のないプロトコル (UDP など) があります。 WCF では、セッションという用語を使用して、接続に似た論理抽象化を意味します。 セッションフル WCF プロトコルは、接続指向のネットワーク プロトコルに似ています。セッションレス WCF プロトコルは、接続のないネットワーク プロトコルに似ています。

チャネル オブジェクト モデルでは、各論理セッションはセッションフル チャネルのインスタンスとしてマニフェストされます。 そのため、クライアントによって作成され、サービスで受け入れられるすべての新しいセッションは、各側の新しいセッションフル チャネルに対応します。 次の図は、上部にセッションレス チャネルの構造と、下部にセッションフル チャネルの構造を示しています。

セッションレス チャネルとセッションフル チャネルの構造を示すフローチャート

クライアントは、新しいセッションフル チャネルを作成し、メッセージを送信します。 サービス側では、チャネル リスナーはこのメッセージを受信し、新しいセッションに属していることを検出して、新しいセッションフル チャネルを作成し、アプリケーションに渡します (チャネル リスナーで AcceptChannel を呼び出すアプリケーションに応答します)。 その後、アプリケーションはこのメッセージと、同じセッションフル チャネルを介して同じセッションで送信されたすべてのメッセージを受信します。

別のクライアント (または同じクライアント) が新しいセッションフルを作成し、メッセージを送信します。 チャネル リスナーは、このメッセージが新しいセッション内にあると検出し、新しいセッションフル チャネルを作成し、プロセスを繰り返します。

セッションがないと、チャネルとセッションの間に相関関係はありません。 そのため、チャネル リスナーは、受信したすべてのメッセージがアプリケーションに配信されるチャネルを 1 つだけ作成します。 メッセージの順序を維持するセッションがないため、メッセージの順序付けもありません。 上の図の上部は、セッションレス メッセージ交換を示しています。

セッションの開始と終了

セッションは、新しいセッションフル チャネルを作成するだけでクライアントで開始されます。 サービスが新しいセッションで送信されたメッセージを受信すると、そのサービス内でプロセスが開始されます。 同様に、セッションはセッション チャネルを閉じることや中止することによって終了します。

これに対する例外は、双方向のセッションフル通信パターンでのメッセージの送受信の両方に使用される IDuplexSessionChannel です。 一方の側がメッセージの送信を停止したいが、メッセージの受信を続ける可能性があるため、 IDuplexSessionChannel を使用すると、メッセージを送信せず、入力セッションを開いたままにしてメッセージを受信し続けることを示す出力セッションを閉じることができるメカニズムがあります。

一般に、セッションは、受信側ではなく、発信側で閉じられます。 つまり、セッションフル出力チャネルを閉じて、セッションをクリーンに終了できます。 セッションフル出力チャネルを閉じると、対応するセッションフル入力チャネルは、IInputChannel.ReceiveのIDuplexSessionChannelを呼び出すアプリケーションに null を返します。

ただし、IInputChannel.ReceiveでIDuplexSessionChannelが null を返し、セッションが既に閉じられていることを示す場合を除き、セッションフル入力チャネルを閉じてはなりません。 IInputChannel.Receive の IDuplexSessionChannel が null を返していない場合に、セッションの多い入力チャネルを閉じると、例外がスローされることがあります。これは、チャネルを閉じている間に、予期しないメッセージを受信することがあるためです。 送信側がセッションを終了する前に受信側がセッションを終了する場合は、入力チャネルで Abort を呼び出す必要があります。これによってセッションが突然終了します。

セッションの多いチャネルの作成

セッションの多いチャネルを作成した場合、セッションを提供するためにチャネルで実行しなければならないことがいくつかあります。 送信側では、チャネルで以下を行う必要があります。

  • 新しいチャネルごとに、新しいセッションを作成し、一意の文字列である新しいセッション ID に関連付けます。 または、スタック内で、作成したチャネルの下にあるセッションの多いチャネルから新しいセッションを取得します。

  • このチャネルを使用して送信された各メッセージについて、チャネルがセッションを作成した場合 (下のレイヤーからセッションを取得するのではなく)、メッセージをセッションに関連付ける必要があります。 プロトコル チャネルの場合、これは通常、SOAP ヘッダーを追加することによって行われます。 トランスポート チャネルの場合、これは通常、新しいトランスポート接続を作成するか、フレーム プロトコルにセッション情報を追加することによって行われます。

  • このチャネルを使用して送信されるメッセージごとに、上記の配信保証を提供する必要があります。 セッションを提供するために以下のチャネルに依存している場合、そのチャネルは配信の保証も提供します。 セッションを自分で提供する場合は、それらの保証をプロトコルの一部として実装する必要があります。 一般に、両方の側で WCF を想定するプロトコル チャネルを作成する場合は、TCP トランスポートまたは Reliable Messaging チャネルが必要になり、いずれか 1 つに依存してセッションが提供される場合があります。

  • チャネルで ICommunicationObject.Close が呼び出されたら、指定したタイムアウトまたは既定のタイムアウトを使用してセッションを閉じるのに必要な作業を実行します。 これは、下のチャネルで Close を呼び出すか (セッションを取得したばかりの場合)、特別な SOAP メッセージを送信したり、トランスポート接続を閉じたりするのと同じくらい簡単です。

  • チャネルで Abort が呼び出されたら、I/O を実行せずにセッションを突然終了します。 これは、何も行っていないか、ネットワーク接続またはその他のリソースを中止することを意味する場合があります。

受信側では、チャネルで以下を行う必要があります。

  • 受信メッセージごとに、チャネル リスナーは、それが属しているセッションを検出する必要があります。 これがセッションの最初のメッセージである場合、チャネル リスナーは新しいチャネルを作成し、呼び出しから IChannelListener<TChannel>.AcceptChannelに返す必要があります。 それ以外の場合、チャネル リスナーは、セッションに対応する既存のチャネルを検索し、そのチャネルを介してメッセージを配信する必要があります。

  • チャネルが (必要な配信保証と共に) セッションを提供している場合、受信側は、メッセージの再注文や受信確認の送信などのアクションを実行する必要がある場合があります。

  • チャネルで Close が呼び出されたら、必要な作業を実行して、指定したタイムアウトまたは既定のタイムアウトのどちらかのセッションを閉じます。 これにより、閉じるタイムアウトの有効期限が切れるのを待っている間にチャネルがメッセージを受信した場合、例外が発生する可能性があります。 これは、メッセージを受信したときに、チャネルが終了状態になっているためです。この場合、例外がスローされることになります。

  • チャネルで Abort が呼び出されたら、I/O を実行せずにセッションを突然終了します。 繰り返しますが、これは何も行っていないか、ネットワーク接続またはその他のリソースの中止を伴う可能性があります。

こちらも参照ください