カスタム ストリームのアップグレード
TCP、名前付きパイプなど、ストリーム指向のデータ伝送機構 (トランスポート) が扱うのは、クライアントとサーバーの間を流れる、連続的なバイト ストリームです。このストリームを実際に作り出すのは Stream オブジェクトです。ストリーム アップグレードでは、クライアントは、オプションのプロトコル階層をチャネル スタックに追加する場合に、相手側の通信チャネルにも同じことをするよう要求します。ストリーム アップグレードは、Stream オブジェクトをアップグレードされたものに置き換える形で実施します。
たとえば、トランスポート ストリームのすぐ上に圧縮ストリームを作成することができます。この場合、元のトランスポート Stream を、それを圧縮 Stream でラップしたものに置き換えます。
オブジェクトを順にラップしていくことにより、ストリーム アップグレードを多重に適用できます。
ストリーム アップグレードの動作
ストリーム アップグレード処理には 4 つのコンポーネントが関与します。
- イニシエータは、必要な処理を起動するコンポーネントです。実行時に、接続先に対して、同じようにチャネル トランスポート層をアップグレードするよう要求する役割があります。
- アクセプタは実際にアップグレードを行うコンポーネントです。接続先からのアップグレード要求を受け取り、可能であれば実際にアップグレードする役割があります。
- プロバイダは、クライアント上にイニシエータ、サーバー上にアクセプタを生成するコンポーネントです。
- バインディング要素は、サービスやクライアントのバインディングに追加され、実行時にプロバイダを生成するコンポーネントです。
なお、多重にアップグレードを適用する場合、イニシエータとアクセプタはステート マシンをカプセル化して、適切な適用順序になるようにします。
ストリーム アップグレードの実装方法
Windows Communication Foundation (WCF) には、次のコンポーネントを実装するために、4 つの abstract クラスがあります。
- System.ServiceModel.Channels.StreamUpgradeInitiator
- System.ServiceModel.Channels.StreamUpgradeAcceptor
- System.ServiceModel.Channels.StreamUpgradeProvider
- System.ServiceModel.Channels.StreamUpgradeBindingElement
カスタム ストリーム アップグレードを実装する手順を以下に示します。これは、クライアント側、サーバー側双方に、ごく単純なストリーム アップグレード処理を組み込む場合の手順です。
- StreamUpgradeInitiator を実装するクラスを作成します。
- InitiateUpgrade メソッドをオーバーライドして、ストリームを入力すると、それをアップグレードしたストリームが返されるようにします。これは同期型のメソッドですが、これに似た非同期型のメソッドもあります。
- GetNextUpgrade メソッドをオーバーライドして、追加のアップグレードがないか確認するようにします。
- StreamUpgradeAcceptor を実装するクラスを作成します。
- AcceptUpgrade メソッドをオーバーライドして、ストリームを入力すると、それをアップグレードしたストリームが返されるようにします。これは同期型のメソッドですが、これに似た非同期型のメソッドもあります。
- CanUpgrade メソッドをオーバーライドして、アップグレード処理中のこの時点で、このアップグレード アクセプタがアップグレード要求に応じることができるかどうかを判断するようにします。
- StreamUpgradeProvider を実装するクラスを作成します。CreateUpgradeAcceptor メソッドおよび CreateUpgradeInitiator メソッドをオーバーライドして、手順 1. および 2. で定義したアクセプタとイニシエータのインスタンスをそれぞれ返すようにします。
- StreamUpgradeBindingElement を実装するクラスを作成します。
- クライアント側の BuildClientStreamUpgradeProvider メソッドとサービス側の BuildServerStreamUpgradeProvider メソッドをオーバーライドします。
- クライアント側の BuildChannelFactory メソッドとサービス側の BuildChannelListener メソッドをオーバーライドして、アップグレード バインディング要素を BindingParameters に追加するようにします。
- サーバー側とクライアント側のバインディングに、新しいストリーム アップグレード バインディング要素を追加します。
セキュリティ アップグレード
ストリーム アップグレードの特別な場合として、セキュリティ アップグレードがあります。
WCF には最初から、セキュリティに関連するストリーム アップグレードを実装するためのバインディング要素が 2 つ組み込まれています。トランスポート レベルのセキュリティ構成は、WindowsStreamSecurityBindingElement および SslStreamSecurityBindingElement にカプセル化されており、これらの要素を構成して、カスタム バインディングに追加することができます。この 2 つのバインディング要素は、クライアント側およびサーバー側のストリーム アップグレード プロバイダを構築する StreamUpgradeBindingElement クラスを拡張したものです。これらのバインディング要素には、セキュリティ ストリーム アップグレード専用のプロバイダ クラスを作成するメソッドが定義されています。これらのメソッドは public ではないので、いずれの場合もバインディング要素をバインディングに追加するだけでセキュリティ アップグレードが可能です。
上記の 2 つのバインディング要素では対応できないセキュリティ上の要求に備え、既述のイニシエータ、アクセプタ、プロバイダの各基底クラスから派生した abstract クラスが 3 つ定義されています。
- System.ServiceModel.Channels.StreamSecurityUpgradeInitiator
- System.ServiceModel.Channels.StreamSecurityUpgradeAcceptor
- System.ServiceModel.Channels.StreamSecurityUpgradeProvider
セキュリティ ストリーム アップグレードを実装する手順も、以上 3 つのクラスから派生することを除き、一般のストリーム アップグレードと同様です。これらのクラスには実行時にセキュリティ情報をやり取りするためのプロパティが追加されているので、これをオーバーライドしてください。
多重アップグレード
追加のアップグレード要求を作成するには、前述の手順を繰り返して、追加の StreamUpgradeProvider およびバインディング要素の拡張を作成し、これをバインディングに追加します。各バインディング要素は、バインディングに追加した順に処理されます。各アップグレード プロバイダは、BuildChannelFactory および BuildChannelListener で、既存のアップグレード バインディング パラメータに、どのように自分自身を積み重ねるかを指定できます。次に、既存のアップグレード バインディング パラメータを、新しい複合アップグレード バインディング パラメータに置き換えます。
あるいは、単一のアップグレード プロバイダで、多重のアップグレードに対応することも可能です。たとえば、セキュリティと圧縮の両方に対応するカスタム ストリーム アップグレード プロバイダを実装できます。次の手順を実行します。
- StreamSecurityUpgradeProvider のサブクラスとして、イニシエータおよびアクセプタを生成するプロバイダ クラスを作成します。
- StreamSecurityUpgradeInitiator のサブクラスを作成し、GetNextUpgrade メソッドをオーバーライドして、圧縮ストリーム、セキュリティ ストリームの順にコンテンツ タイプを返すようにします。
- StreamSecurityUpgradeAcceptor のサブクラスを作成し、CanUpgrade メソッドをオーバーライドして、独自のコンテンツ タイプに応じた処理をするようにします。
- ストリームは、GetNextUpgrade および CanUpgrade をそれぞれ呼び出した後にアップグレードされます。
関連項目
リファレンス
StreamUpgradeInitiator
StreamSecurityUpgradeInitiator
StreamUpgradeAcceptor
StreamSecurityUpgradeAcceptor
StreamUpgradeProvider
StreamSecurityUpgradeProvider
StreamUpgradeBindingElement
SslStreamSecurityBindingElement
WindowsStreamSecurityBindingElement