セッションの使用
Windows Communication Foundation (WCF) アプリケーションにおいては、メッセージのグループを "セッション" によって関連付けて通信を行います。 WCF セッションは、ASP.NET アプリケーションで使用できるセッション オブジェクトとは異なるものであり、サポートされる動作と制御する方法が異なります。 ここでは、WCF アプリケーションのセッションで有効になる諸機能とそれらの使用方法について説明します。
Windows Communication Foundation アプリケーションのセッション
サービス コントラクトでセッションが必要であると指定されている場合、すべての呼び出し (つまり、呼び出しをサポートする基本的なメッセージ交換) を同じメッセージ交換の一部にする必要があります。 セッションが許可されるが必須ではないコントラクトの場合、クライアントは、接続した後にセッションを確立できます。また、セッションを確立しないままにしておくこともできます。 セッションが終了したのに、同じチャネルでメッセージが送信されると、例外がスローされます。
WCF セッションには、次の主な概念的特徴があります。
呼び出し側アプリケーション (WCF クライアント) によって明示的に開始および終了される。
セッション中に配信されたメッセージは、受信された順に処理される。
セッションはメッセージのグループを相互に関連付けて通信を行う。 関連付けにはさまざまな種類があります。 たとえば、あるセッション ベースのチャネルでは、共有ネットワーク接続に基づいてメッセージが相互に関連付けられる一方、別のセッション ベースのチャネルでは、メッセージ本文にある共有タグに基づいてメッセージが相互に関連付けられます。 セッションから派生可能な機能は、相互関連付けの性質によって異なります。
WCF セッションに関連付けられた一般的なデータ ストアはありません。
ASP.NET アプリケーションの System.Web.SessionState.HttpSessionState クラスに精通している場合は、この種のセッションと WCF セッションの間に次のような相違があることがわかります。
ASP.NET セッションは、常にサーバーによって開始される。
ASP.NET セッションは暗黙で順序指定されない。
ASP.NET セッションは、要求にまたがる一般的なデータ ストレージ機構を提供する。
このトピックの内容:
サービス モデル レイヤーにおいてセッション ベースのバインディングを使用する場合の既定の実行動作。
WCF のセッション ベースのシステム提供バインディングが提供する機能の種類。
セッションの要件を宣言するコントラクトの作成方法。
セッションの作成と終了、およびセッションとサービス インスタンスの関係を理解し、制御する方法。
セッションを使用した既定の実行動作
セッションの開始を試みるバインディングは、 セッション ベース のバインディングと呼ばれます。 サービス コントラクトで、セッション ベースのバインディングを要求、許可、または拒否するように指定するときは、サービス コントラクト インターフェイス (またはクラス) の ServiceContractAttribute.SessionMode プロパティを System.ServiceModel.SessionMode 列挙値に設定します。 このプロパティの既定値は Allowed です。これは、クライアントが WCF サービス実装でセッション ベースのバインディングを使用すると、サービスが提供されたセッションを確立して使用することを意味しす。
WCF サービスがクライアント セッションを受け入れると、既定で次の機能が有効になります。
WCF クライアント オブジェクト間のすべての呼び出しは、同一のサービス インスタンスによって処理されます。
さまざまなセッション ベースのバインディングによって追加機能が提供されます。
システム指定のセッションの種類
セッション ベースのバインディングは、サービス インスタンスと特定のセッションとの既定の関連付けをサポートします。 ただし、前のセッション ベースのインスタンス化制御を有効にすることに加えて、セッション ベースのバインディングごとにサポートされる機能も異なります。
WCF には、次の種類のセッション ベースのアプリケーション動作が用意されています。
2 者間の通信で特定のセキュリティ保護されたメッセージ交換について両者の合意が成立している場合、 System.ServiceModel.Channels.SecurityBindingElement は、セキュリティ ベースのセッションをサポートします。 詳細については、「サービスのセキュリティ保護」を参照してください。 たとえば、セキュリティ セッションと信頼できるセッションの両方のサポートを含む System.ServiceModel.WSHttpBinding バインディングは、既定では、メッセージを暗号化してデジタル署名を行うセキュリティで保護されたセッションのみを使用します。
System.ServiceModel.NetTcpBinding バインディングは、TCP/IP ベースのセッションをサポートしており、すべてのメッセージがソケット レベルの接続によって関連付けられます。
WS-ReliableMessaging 仕様を実装する System.ServiceModel.Channels.ReliableSessionBindingElement 要素は、メッセージを順番に 1 回だけ配信するように構成できる、信頼できるセッションをサポートします。これにより、メッセージ交換時にメッセージが複数のノードを通過する場合でもメッセージが受信されます。 詳細については、「信頼できるセッション」を参照してください。
System.ServiceModel.NetMsmqBinding バインディングは、MSMQ データグラム セッションを提供します。 詳細については、WCF のキューに関するページを参照してください。
SessionMode プロパティを設定しても、コントラクトが必要とするセッションの種類は指定されず、コントラクトがセッションを必要とすることだけが指定されます。
セッションを必要とするコントラクトの作成
セッションを必要とするコントラクトを作成するのは、サービス コントラクトで宣言する操作のグループをすべて同じセッション内で実行し、メッセージを順番に配信する必要がある場合です。 サービス コントラクトが必要とするセッションのサポート レベルをアサートするには、サービス コントラクト インターフェイスまたはクラスの ServiceContractAttribute.SessionMode プロパティを System.ServiceModel.SessionMode 列挙値に設定して以下を指定します。
コントラクトがセッションを必要とするかどうか。
コントラクトで、クライアントによるセッションの確立を許可するかどうか。
コントラクトでセッションを禁止するかどうか。
ただし、 SessionMode プロパティを設定しても、コントラクトが必要とするセッション ベースの動作の種類は指定されません。 これは、サービスの (通信チャネルを作成する) 構成済みバインディングが、サービスの実装時にセッションを確立する、確立しない、または確立できるかを実行時に確認するよう WCF に指示します。 ここでもバインディングは、選択する任意の種類のセッション ベースの動作 (セキュリティ セッション、トランスポート セッション、信頼できるセッション、またはこれらの一定の組み合わせ) によってこの要件を満たすことができます。 正確な動作は、選択した System.ServiceModel.SessionMode 値によって決まります。 サービスの構成済みバインディングが SessionModeの値に一致しない場合は、例外がスローされます。 セッションをサポートするバインディングと、それが作成するチャネルは、セッション ベースのバインディングまたはチャネルと呼ばれます。
次のサービス コントラクトは、 ICalculatorSession
のすべての操作をセッション内で交換する必要があることを指定しています。 Equals
メソッドを除き、どの操作も呼び出し元に値を返しません。 ただし、 Equals
メソッドはパラメーターを受け取らないため、データが既に他の操作に渡されているセッション内では、ゼロ以外の値しか返すことができません。 このコントラクトでは、セッションが正常に機能する必要があります。 特定のクライアントに関連付けられているセッションがないと、サービス インスタンスは、そのクライアントが以前に送信したデータを知ることができません。
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples", SessionMode=SessionMode.Required)]
public interface ICalculatorSession
{
[OperationContract(IsOneWay=true)]
void Clear();
[OperationContract(IsOneWay = true)]
void AddTo(double n);
[OperationContract(IsOneWay = true)]
void SubtractFrom(double n);
[OperationContract(IsOneWay = true)]
void MultiplyBy(double n);
[OperationContract(IsOneWay = true)]
void DivideBy(double n);
[OperationContract]
double Equals();
}
<ServiceContract(Namespace:="http://Microsoft.ServiceModel.Samples", SessionMode:=SessionMode.Required)> _
Public Interface ICalculatorSession
<OperationContract(IsOneWay:=True)> _
Sub Clear()
<OperationContract(IsOneWay:=True)> _
Sub AddTo(ByVal n As Double)
<OperationContract(IsOneWay:=True)> _
Sub SubtractFrom(ByVal n As Double)
<OperationContract(IsOneWay:=True)> _
Sub MultiplyBy(ByVal n As Double)
<OperationContract(IsOneWay:=True)> _
Sub DivideBy(ByVal n As Double)
<OperationContract()> _
Function Equal() As Double
End Interface
サービスがセッションを許可した場合は、クライアントがセッションを開始するとセッションが確立され、使用されますが、許可しない場合は、セッションが確立されません。
セッションとサービス インスタンス
WCF で既定のインスタンス化動作を使用した場合は、WCF クライアント オブジェクト間のすべての呼び出しが同じサービス インスタンスによって処理されます。 そのため、アプリケーション レベルでは、セッションは、ローカル呼び出し動作と同様のアプリケーション動作を有効にすると考えることができます。 たとえば、ローカル オブジェクトを作成するときは、次のような流れになります。
コンストラクターが呼び出されます。
これ以降に WCF クライアント オブジェクト参照に対して行われる呼び出しは、すべて同じオブジェクト インスタンスによって処理されます。
オブジェクト参照が破棄されると、デストラクターが呼び出されます。
既定のサービス インスタンス動作を使用している限り、セッションでは、クライアントとサービス間で同様の動作が有効になります。 サービス コントラクトがセッションを必要としたり、サポートしたりする場合は、 IsInitiating プロパティと IsTerminating プロパティを設定することで、1 つ以上のコントラクト操作をセッションの開始または終了としてマークできます。
開始操作 は、新しいセッションの最初の操作として呼び出す必要がある操作です。 開始操作以外の操作は、少なくとも 1 つの開始操作が呼び出された後にしか呼び出すことはできません。 そのため、サービス インスタンスの開始に適した入力をクライアントから取得するように設計された開始操作を宣言することで、サービスに対する一種のセッション コンストラクターを作成できます (ただし、状態はセッションに関連付けられ、サービス オブジェクトに関連付けられません)。
終了操作は、開始操作とは逆に、既存のセッションの最終メッセージとして呼び出す必要がある操作です。 既定では、WCF は、サービスが関連付けられているセッションが閉じられた後に、サービス オブジェクトとそのコンテキストを再利用します。 そのため、サービス インスタンスの終了に適した関数を実行するように設計された終了操作を宣言することで、一種のデストラクターを作成できます。
注意
既定の動作は、ローカルのコンストラクターとデストラクターに似ていますが、あくまで似ているだけです。 任意の WCF サービス操作を開始操作または終了操作として使用できます。また、両方を同時に兼ねることもできます。 さらに既定では、開始操作は、任意の順序で何回でも呼び出すことができます。そのため、 System.ServiceModel.InstanceContext オブジェクトを操作することでサービス インスタンスの有効期間を明示的に制御しない限り、セッションが確立されインスタンスに関連付けられた後に、追加セッションは作成されません。 また、状態はセッションに関連付けられ、サービス オブジェクトには関連付けられません。
たとえば、前の例で使用した ICalculatorSession
コントラクトで、WCF クライアント オブジェクトが、他の操作に先立って最初に Clear
操作を呼び出す必要があり、さらにこの WCF クライアント オブジェクトとのセッションが、Equals
操作を呼び出したときに終了する必要があるとします。 次のコード例は、この要件を強制的に適用するコントラクトを示しています。 セッションを開始するにはまずClear
を呼び出す必要があります。 Equals
を呼び出すとセッションが終了します。
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples", SessionMode=SessionMode.Required)]
public interface ICalculatorSession
{
[OperationContract(IsOneWay=true, IsInitiating=true, IsTerminating=false)]
void Clear();
[OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = false)]
void AddTo(double n);
[OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = false)]
void SubtractFrom(double n);
[OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = false)]
void MultiplyBy(double n);
[OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = false)]
void DivideBy(double n);
[OperationContract(IsInitiating = false, IsTerminating = true)]
double Equals();
}
<ServiceContract(Namespace:="http://Microsoft.ServiceModel.Samples", SessionMode:=SessionMode.Required)> _
Public Interface ICalculatorSession
<OperationContract(IsOneWay:=True, IsInitiating:=True, IsTerminating:=False)> _
Sub Clear()
<OperationContract(IsOneWay:=True, IsInitiating:=False, IsTerminating:=False)> _
Sub AddTo(ByVal n As Double)
<OperationContract(IsOneWay:=True, IsInitiating:=False, IsTerminating:=False)> _
Sub SubtractFrom(ByVal n As Double)
<OperationContract(IsOneWay:=True, IsInitiating:=False, IsTerminating:=False)> _
Sub MultiplyBy(ByVal n As Double)
<OperationContract(IsOneWay:=True, IsInitiating:=False, IsTerminating:=False)> _
Sub DivideBy(ByVal n As Double)
<OperationContract(IsInitiating:=False, IsTerminating:=True)> _
Function Equal() As Double
End Interface
サービスは、クライアントとのセッションを開始しません。 WCF クライアント アプリケーションにおいては、セッション ベースのチャネルの有効期間とセッション自体の有効期間の間に直接的な関係があります。 そのため、クライアントは、新しいセッション ベースのチャネルを作成することによって新しいセッションを作成し、セッション ベースのチャネルを正常に閉じることによって、既存のセッションを破棄します。 クライアントは、次のいずれかを呼び出してサービス エンドポイントとのセッションを開始します。
ICommunicationObject.Open の呼び出しによって返されるチャネルの ChannelFactory<TChannel>.CreateChannel。
ServiceModel メタデータ ユーティリティ ツール (Svcutil.exe) によって生成される WCF クライアント オブジェクトの ClientBase<TChannel>.Open。
いずれかの型の WCF クライアント オブジェクトの開始操作 (既定では、すべての操作が開始操作です)。 最初の操作が呼び出されると、WCF クライアント オブジェクトが自動的にチャネルを開き、セッションを開始します。
通常は、クライアントが次のいずれかを呼び出して、サービス エンドポイントとのセッションを終了します。
ICommunicationObject.Close の呼び出しによって返されるチャネルの ChannelFactory<TChannel>.CreateChannel。
Svcutil.exe によって生成された WCF クライアント オブジェクトの ClientBase<TChannel>.Close。
いずれかの型の WCF クライアント オブジェクトの終了操作 (既定では、終了操作はありません。コントラクトで終了操作を明示的に指定する必要があります)。 最初の操作が呼び出されると、WCF クライアント オブジェクトが自動的にチャネルを開き、セッションを開始します。
例については、「 How to: Create a Service That Requires Sessions 」、および「 Default Service Behavior 」や「 Instancing 」のサンプルを参照してください。
クライアントとセッションの詳細については、「WCF クライアントを使用したサービスへのアクセス」を参照してください。
InstanceContext 設定と対話するセッション
コントラクト内の SessionMode 列挙と、チャネルと特定のサービス オブジェクト間の関連付けを制御する ServiceBehaviorAttribute.InstanceContextMode プロパティの間には相互作用があります。 詳細については、「セッション、インスタンス化、およびコンカレンシー」を参照してください。
InstanceContext オブジェクトの共有
ユーザーが自ら関連付けを行うことにより、どの InstanceContext オブジェクトに、どのセッション ベースのチャネルまたは呼び出しを関連付けるかを制御することもできます。
セッションとストリーミング
大量のデータを転送する場合、メッセージ全体をメモリ内でバッファー化および処理するという既定動作の代わりに、WCF のストリーミング転送モードを使用することができます。 セッション ベースのバインディングでストリーミングを呼び出すと、予期しない動作を引き起こすことがあります。 すべてのストリーミング呼び出しは単一のチャネル (データグラム チャネル) を通じて行われますが、このチャネルは使用されるバインディングがセッションを使用するように構成されている場合であっても、セッションをサポートしません。 セッション ベースのバインディングによって複数のクライアントが同一のサービス オブジェクトに対してストリーミング呼び出しを行う場合、このサービス オブジェクトのコンカレンシー モードが単一に設定され、インスタンス コンテキスト モードが PerSession
に設定されていると、すべての呼び出しがこのデータグラム チャネルを通過する必要があるため、同時に処理される呼び出しは 1 つに限られることになります。 そのため、1 つ以上のクライアントがタイムアウトとなる可能性があります。サービス オブジェクトの InstanceContextMode
を PerCall
に設定するか、またはコンカレンシー モードを複数に設定することで、この問題を回避できます。
注意
この場合、利用可能になる "セッション" は 1 つしかないため、MaxConcurrentSessions は効力を失います。