ユーザー定義バインディングの作成
システムから提供されないバインディングを作成する方法はいくつかあります。
バインド要素を格納するコンテナーである CustomBinding クラスに基づいてカスタム バインドを作成します。 次に、カスタム バインドをサービス エンドポイントに追加します。 カスタム バインディングは、プログラムで作成することも、アプリケーションの構成ファイルに作成することもできます。 アプリケーション構成ファイルのバインド要素を使用するには、バインド要素で BindingElementExtensionElement を拡張する必要があります。 カスタム バインディングの詳細については、「カスタム バインディング」と CustomBinding を参照してください。
標準バインディングの派生クラスを作成できます。 たとえば、WSHttpBinding の派生クラスを作成して CreateBindingElements メソッドをオーバーライドし、バインド要素を取得してカスタム バインドを挿入したり、セキュリティ用の特定の値を確立したりできます。
新しい Binding 型を作成して、バインディング実装全体を完全に制御することができます。
バインド要素の順序
各バインド要素は、メッセージの送信または受信時の処理手順を表します。 実行時に、バインディング要素により、送受信チャネル スタックの作成に必要なチャネルとリスナーが作成されます。
バインド要素には主に、プロトコル バインド要素、エンコーディング バインド要素、トランスポート バインド要素という 3 つの種類があります。
プロトコル バインド要素 : この要素はメッセージで動作する上位処理ステップを表します。 このバインド要素で作成したチャネルとリスナーを使って、メッセージ内容の追加、削除、変更が可能です。 特定のバインディングには、それぞれが BindingElement を継承する任意の数のプロトコル バインド要素を含めることができます。 Windows Communication Foundation (WCF) には、ReliableSessionBindingElement や SymmetricSecurityBindingElement など、いくつかのプロトコル バインディング要素が含まれます。
エンコーディング バインド要素 : この要素は、メッセージとネットワーク転送が可能なエンコーディングとの間の変換を表します。 一般的な WDF バインディングには、エンコード バインディング要素が 1 つだけ含まれます。 エンコーディング バインド要素の例として、MtomMessageEncodingBindingElement、BinaryMessageEncodingBindingElement、TextMessageEncodingBindingElement などがあります。 エンコーディング バインド要素がバインディングに指定されていない場合、既定のエンコーディングが使用されます。 既定値は、トランスポートが HTTP の場合はテキスト、それ以外の場合はバイナリです。
トランスポート バインド要素 : この要素は、トランスポート プロトコルでのエンコーディング メッセージの送信を表します。 一般的な WCF バインディングには、TransportBindingElement から派生したトランスポート バインディング要素が 1 つだけ含まれます。 トランスポート バインド要素の例として、TcpTransportBindingElement、HttpTransportBindingElement、NamedPipeTransportBindingElement などがあります。
新しいバインディングを作成する場合、バインド要素の追加順序が重要になります。 バインド要素は必ず次の順序で追加します。
レイヤー | Options | 必須 |
---|---|---|
トランザクション フロー | System.ServiceModel.Channels.TransactionFlowBindingElement | いいえ |
[信頼性] | System.ServiceModel.Channels.ReliableSessionBindingElement | いいえ |
セキュリティ | System.ServiceModel.Channels.SecurityBindingElement | いいえ |
複合二重 | System.ServiceModel.Channels.CompositeDuplexBindingElement | いいえ |
エンコード | テキスト、バイナリ、MTOM、カスタム | はい* |
トランスポート | TCP、名前付きパイプ、HTTP、HTTPS、MSMQ、およびカスタム | はい |
*エンコードは各バインディングに必要であるため、エンコードが指定されていない場合は、WCF によって既定のエンコードが自動的に追加されます。 既定値は、HTTP および HTTPS トランスポートの場合はテキスト/XML、それ以外の場合はバイナリです。
新しいバインド要素の作成
WCF が提供する、BindingElement から派生した型のほかに、独自のバインディング要素を作成できます。 これにより、他のシステムが提供する型を使ってスタックに組み込むことのできる独自の BindingElement を作成して、バインディングのスタックを作成する方法や、バインディングのスタックに追加するコンポーネントをカスタマイズできます。
たとえば、メッセージをデータベースに記録する機能を持つ LoggingBindingElement
を実装する場合、それをチャネル スタックのトランスポート チャネルの上に配置する必要があります。 この場合、アプリケーションでは、次の例に示すように、LoggingBindingElement
と共に TcpTransportBindingElement
が組み込まれたカスタム バインディングが作成されます。
Binding customBinding = new CustomBinding(
new LoggingBindingElement(),
new TcpTransportBindingElement()
);
新しいバインド要素を記述する方法は、機能性の詳細によって異なります。 サンプルの 1 つ、「トランスポート: UDP」では、1 種類のバインディング要素の実装方法を詳細に説明しています。
新しいバインディングの作成
ユーザーが作成するバインド要素は、2 つの方法で使用できます。 前のセクションでは、カスタム バインドを使用する 1 番目の方法が説明されています。 カスタム バインドを使用すれば、バインド要素の任意のセットに基づいて独自のバインディングを作成できます。ユーザーが作成するバインディング エレメントもこれに含まれます。
2 つ以上のアプリケーションでバインディングを使用する場合、独自のバインディングを作成し、Binding を拡張します。 これにより、カスタム バインドを使う必要があるたびに、手動でカスタム バインドを作成する必要性を回避できます。 ユーザー定義のバインディングを使用して、バインディングの動作を定義したり、ユーザー定義のバインド要素を格納することができます。 また、事前パッケージングであるため、使用するたびにバインディングを再作成する必要はありません。
ユーザー定義のバインディングは、少なくとも CreateBindingElements メソッドと Scheme プロパティを実装する必要があります。
CreateBindingElements メソッドは、バインディングのバインド要素を格納している新しい BindingElementCollection を返します。 このコレクションは順序付けられており、始めにプロトコル バインド要素を格納し、次にエンコーディング バインド要素、その次にトランスポート バインド要素を格納する必要があります。 WCF のシステム指定のバインド要素を使用する場合は、「カスタム バインディング」に指定されているバインディング要素の順序付けルールに従う必要があります。 このコレクションから、ユーザー定義のバインディング クラス内で参照されるオブジェクトを参照すべきではありません。このため、バインディングの作成者は、Clone()
を呼び出すたびに BindingElementCollection の CreateBindingElements を返す必要があります。
Scheme プロパティは、バインディングで使用するトランスポート プロトコルの URI スキームを表します。 たとえば、WSHttpBinding および NetTcpBinding は、Scheme プロパティからそれぞれ、"http" および "net.tcp" を返します。
ユーザー定義バインディングのオプション メソッドとプロパティの完全な一覧については、Binding を参照してください。
例
このサンプルでは、プロファイル バインディングを、SampleProfileUdpBinding
から派生した Binding に実装します。 SampleProfileUdpBinding
は、最大で 4 つのバインディング要素を格納します。1 つはユーザー作成の UdpTransportBindingElement
で、3 つはシステム指定のTextMessageEncodingBindingElement
、CompositeDuplexBindingElement
、ReliableSessionBindingElement
です。
public override BindingElementCollection CreateBindingElements()
{
BindingElementCollection bindingElements = new BindingElementCollection();
if (ReliableSessionEnabled)
{
bindingElements.Add(session);
bindingElements.Add(compositeDuplex);
}
bindingElements.Add(encoding);
bindingElements.Add(transport);
return bindingElements.Clone();
}
双方向コントラクトのセキュリティ制限
すべてのバインド要素どうしに互換性があるわけではありません。 特に双方向コントラクトで使用する場合、セキュリティ バインド要素にはいくつかの制限があります。
ワンショット セキュリティ
<message> 構成要素の negotiateServiceCredential
属性を false
に設定すると、必要なすべてのセキュリティ資格情報を 1 つのメッセージで送信する、"ワンショット" セキュリティを実装できます。
ワンショット認証は双方向コントラクトでは動作しません。
要求/応答コントラクトでは、セキュリティ バインド要素の下にあるバインディング スタックで IRequestChannel インスタンスまたは IRequestSessionChannel インスタンスの作成がサポートされている場合にのみ、ワンショット認証は動作します。
一方向コントラクトでは、セキュリティ バインド要素の下にあるバインディング スタックで IRequestChannel、IRequestSessionChannel、IOutputChannel、または IOutputSessionChannel の各インスタンスの作成がサポートされている場合にのみ、ワンショット認証は動作します。
クッキー モードのセキュリティ コンテキスト トークン
クッキー モードのセキュリティ コンテキスト トークンは、双方向コントラクトでは使用できません。
要求/応答コントラクトでは、セキュリティ バインド要素の下にあるバインディング スタックで IRequestChannel インスタンスまたは IRequestSessionChannel インスタンスの作成がサポートされている場合にのみ、クッキー モードのセキュリティ コンテキスト トークンは動作します。
一方向コントラクトでは、セキュリティ バインド要素の下にあるバインディング スタックで IRequestChannel インスタンスまたは IRequestSessionChannel インスタンスの作成がサポートされている場合にのみ、クッキー モードのセキュリティ コンテキスト トークンは動作します。
セッション モードのセキュリティ コンテキスト トークン
双方向コントラクトでは、セッション モードの SCT (セキュリティ コンテキスト トークン) は、セキュリティ バインド要素の下にあるバインディング スタックで IDuplexChannel インスタンスまたは IDuplexSessionChannel インスタンスの作成がサポートされている場合に動作します。
要求/応答コントラクトでは、セッション モードの SCT は、セキュリティ バインド要素の下にあるバインディング スタックで IDuplexChannel、IDuplexSessionChannel、IRequestChannel、または IRequestSessionChannel の各インスタンスの作成がサポートされている場合に動作します。
一方向コントラクトでは、セッション モードの SCT は、セキュリティ バインド要素の下にあるバインディング スタックで IDuplexChannel、IDuplexSessionChannel、IRequestChannel、または IRequestSessionChannel の各インスタンスの作成がサポートされている場合に動作します。
標準バインディングからの派生
まったく新しいバインディング クラスを作成する代わりに、システムから提供される既存のバインディングの 1 つを拡張することができます。 前述の場合と同様、CreateBindingElements メソッドと Scheme プロパティをオーバーライドする必要があります。