カスタム エンコーダー

このトピックでは、カスタム エンコーダーを作成する方法について説明します。

Windows Communication Foundation (WCF) では、バインディングを使用して、エンドポイント間のネットワーク全体でデータを転送する方法を指定します。 バインディングは、一連のバインディング要素で構成されます。 バインディングには、セキュリティなどのプロトコル バインディング要素 (省略可能)、メッセージ エンコーダーのバインディング要素 (必須)、およびトランスポート バインディング要素 (必須) が含まれます。 メッセージ エンコーダーは、メッセージ エンコーディング バインド要素で表されます。 WCF には、バイナリ、MTOM (Message Transmission Optimization Mechanism)、テキストという 3 つのメッセージ エンコーダーが含まれます。

メッセージ エンコーディング バインド要素は、送信する Message をシリアル化してそれをトランスポートに渡すか、シリアル化された形式のメッセージをトランスポートから受信して、それをプロトコル層 (ある場合) またはアプリケーション (プロトコル層がない場合) に渡します。

メッセージ エンコーダーは、Message インスタンスと物理メッセージ形式を相互に変換します。 エンコーダーは、チャネル スタックのトランスポート層の上に位置すると説明されていますが、トランスポート層の内部に存在します。 トランスポート (HTTP など) は、トランスポート標準の要件に従ってメッセージの書式設定を行います。 エンコーダー (テキスト XML など) は、単にメッセージのエンコードを行います。

既存のクライアントまたはサーバーに接続する場合、特定のメッセージ エンコーディングを使用する選択ができない場合があります。 ただし、WCF サービスは、それぞれが異なるメッセージ エンコーダーを使用する複数のエンドポイントからアクセスできるようにすることができます。 1 つのエンコーダーでサービスの対象ユーザー全体を網羅しない場合、複数のエンドポイントにサービスを公開することを検討します。 これによりクライアント アプリケーションはそのアプリケーションに最も適したエンドポイントを選択できます。 複数のエンドポイントを使用することにより、さまざまなメッセージ エンコーダーの利点を他のバインド要素と組み合わせることが可能になります。

システム指定のエンコーダー

WCF では、最も一般的なアプリケーション シナリオに合わせて設計されたシステム指定のバインディングがいくつか用意されています。 これらのバインディングは、それぞれトランスポート、メッセージ エンコーダー、その他のオプション (セキュリティなど) を組み合わせます。 このトピックでは、WCF に含まれる TextBinary、および MTOM メッセージ エンコーダーの拡張方法、つまり、独自のカスタム エンコーダーの作成方法について説明します。 テキスト メッセージ エンコーダーは、通常の XML のエンコーディングに加えて、SOAP のエンコーディングもサポートします。 テキスト メッセージ エンコーダーの通常の XML エンコーディング モードは、テキスト ベースの SOAP エンコーディングと区別するために、POX ("Plain Old XML") エンコーダーと呼ばれます。

システム指定のバインディングによって提供されるバインディング要素の組み合わせの詳細については、「トランスポートの選択」内の対応するセクションを参照してください。

システム標準のエンコーダーの操作方法

エンコーディングは、MessageEncodingBindingElement からの派生クラスを使用してバインディングに追加します。

WCF は、テキスト、バイナリ、および Message Transmission Optimization Mechanism (MTOM) の各エンコードに対応可能な MessageEncodingBindingElement クラスから派生した、次の種類のバインド要素を提供します。

  • TextMessageEncodingBindingElement : 相互運用性は最も高く、効率は最も低い、XML メッセージ用のエンコーダー。 Web サービスまたは Web サービス クライアントは、一般に、テキスト形式の XML を認識できます。 ただし、大きいブロックのバイナリ データをテキストとして転送するのは効率的ではありません。

  • BinaryMessageEncodingBindingElement : バイナリベースの XML メッセージで使用される、文字エンコーディングおよびメッセージのバージョン管理を指定するバインド要素を表します。 これは最も効率的なエンコード オプションですが、WCF エンドポイント以外ではサポートされないため、相互運用性は最も低くなります。

  • MtomMessageEncodingBindingElement : Message Transmission Optimization Mechanism (MTOM) エンコードを使用するメッセージの文字エンコードおよびメッセージ バージョン管理を指定するバインド要素を表します。 MTOM は、WCF メッセージでバイナリ データを転送するための効率的なテクノロジです。 MTOM エンコーダーは、効率と相互運用性のバランスをとろうとします。 MTOM エンコーディングは、ほとんどの XML をテキスト形式で転送しますが、大きいサイズのバイナリ データ ブロックはテキストに変換せずにそのまま転送することによって最適化します。

バインド要素は、バイナリ、MTOM、またはテキストの MessageEncoderFactory を作成します。 ファクトリは、バイナリ、MTOM、またはテキストの MessageEncoderFactory を作成します。 通常、インスタンスは 1 つだけあります。 ただし、セッションを使用すると、異なるエンコーダーを各セッションに提供できます。 バイナリ エンコーダーでは、これを利用して動的ディクショナリ (XML インフラストラクチャを参照) を調整します。

ReadMessage メソッドと WriteMessage メソッドは、エンコーダーのコアです。 このメソッドは、ストリームまたは Byte 配列からのメッセージの読み取りに対応します。 バイト配列は、トランスポートをバッファー モードで操作している場合に使用されます。 メッセージはストリームに常に書き込まれます。 トランスポートでメッセージをバッファーする必要がある場合は、バッファリングを行うストリームが提供されます。

残りのメンバーは、サポート コンテンツ、メディア タイプ、および MessageVersion を処理します。 トランスポートは、このエンコーダー メソッドを呼び出して、受信メッセージがデコード可能かどうかをテストするか、または送信メッセージがこのエンコーダーに対して有効かどうかを決定します。

3 つのそれぞれのエンコーダー実装は、特定のエンコーディングに関連するプロパティを追加し、完全に構成可能です。 また、エンコーダーは、安全な既定値を持つリーダーのクォータも公開しています。 クォータの詳細については、XML インフラストラクチャを参照してください。

システム標準のエンコーダーの機能

システム標準のエンコーダーは多くの機能を提供します。

Pooling

各エンコーダー実装は、可能な限りプールを試みます。 マネージド コードのパフォーマンスを向上するには、割り当てを減らすことが重要です。 このプールを実現するには、実装で SynchronizedPool クラスを使用します。 C# ファイルには、このクラスで使用する追加の最適化に関する記述を含めます。

メッセージごとに新しい XmlDictionaryReader および XmlDictionaryWriter インスタンスを割り当てるのを避けるため、これらのインスタンスをプールして再初期化します。 リーダーについては、OnClose の呼び出し時に Close() コールバックでリーダーが再利用されます。 また、エンコーダーでは、メッセージを作成するときに使用するいくつかのメッセージ状態オブジェクトが再利用されます。 このプールのサイズは、MaxReadPoolSize から派生した 3 つの各クラスの MaxWritePoolSize プロパティと MessageEncodingBindingElement プロパティによって構成可能です。

バイナリ エンコーディング

バイナリ エンコーディングでセッションを使用する場合、動的ディクショナリの文字列をメッセージの受信者と通信する必要があります。 これを行うには、メッセージのプレフィックスに動的ディクショナリの文字列を指定します。 受信側では、その文字列を取り除いて、セッションに追加し、メッセージ処理を行います。 ディクショナリの文字列を正しく渡すには、トランスポートをバッファーする必要があります。

文字列は、内部 AddSessionInformationToMessage メソッドによってメッセージに追加されます。 文字列は、メッセージの先頭に UTF-8 として追加され、その長さがプレフィックスに指定されます。 次にディクショナリ ヘッダー全体のプレフィックスにそのデータ長が指定されます。 内部 ExtractSessionInformationFromMessage メソッドにより逆操作が実行されます。

動的ディクショナリ キーの処理に加え、バッファーされセッションの多いメッセージが独自の方法で受信されます。 ドキュメントでリーダーを作成して処理する代わりに、バイナリ エンコーダーは、内部 MessagePatterns クラスを使用してバイナリ ストリームを分解します。 つまり、ほとんどのメッセージには、WCF で生成されたときに特定の順序で表示される特定のセットのヘッダーがあります。 想定を基にしたパターン システムによりメッセージは分割されます。 成功した場合は、XML の解析を行わずに MessageHeaders オブジェクトを初期化します。 成功しなかった場合は、標準の方法に戻ります。

MTOM エンコーディング

MtomMessageEncodingBindingElement クラスには、MaxBufferSize という追加の構成プロパティがあります。 これには、メッセージ読み取り中にバッファーできるデータ量の上限が設けられています。 すべての MIME パートを 1 つのメッセージに再アセンブルするために、XML 情報セット (Infoset) または他の MIME パートをバッファーすることが必要な場合もあります。

HTTP を正しく操作するために、内部 MTOM メッセージ エンコーダーのクラスでは、GetContentType (内部) や WriteMessage (パブリックで、オーバーライド可能) の内部 API がいくつか用意されています。 HTTP ヘッダーの値を MIME ヘッダーの値と一致させるには、多くの通信を行う必要があります。

内部的に、MTOM メッセージ エンコーダーは、WCF のテキスト リーダーを使用しており、テキスト エンコーダーに似ています。 主な違いは、Base-64 エンコーディングに変換せずにメッセージ バイトに埋め込むことで、大きいサイズのバイナリ (バイナリ ラージ オブジェクト (BLOB) と呼びます) を最適化する点です。 代わりに、この BLOB は抽出され、MIME 添付として参照されます。

独自のエンコーダーの作成

独自のカスタム メッセージ エンコーダーを実装するには、次の抽象基本クラスのカスタム実装を提供する必要があります。

メッセージのメモリ内表現からストリームに書き込むことのできる表現への変換は、 MessageEncoder クラスにカプセル化されており、このクラスは、特定の種類の XML エンコーディングをサポートする XML リーダーおよび XML ライターに対するファクトリとして機能します。

  • オーバーライドを必要とする、このクラスの主要なメソッドを次に示します。

  • WriteMessageMessageEncodingBindingElement オブジェクトを受け取り、それを Stream オブジェクトに書き込みます。

  • ReadMessageStream オブジェクトと最大ヘッダー サイズを受け取り、Message オブジェクトを返します。

これらのメソッドに記述するコードは、標準トランスポート プロトコルとカスタマイズしたエンコーディングの間の変換処理です。

次に、カスタム エンコーダーを作成するファクトリ クラスをコーディングする必要があります。 Encoder をオーバーライドして、独自のカスタム MessageEncoder のインスタンスを返します。

次に、MessageEncoderFactory メソッドをオーバーライドしてこのファクトリのインスタンスを返すようにすることで、サービスまたはクライアントの構成に使用されるバインド要素スタックにカスタム CreateMessageEncoderFactory を接続します。

WCF には、"カスタム メッセージ エンコーダー: カスタム テキスト エンコーダー" と "カスタム メッセージ エンコーダー: 圧縮エンコーダー" という、このプロセスをサンプル コードで説明する 2 つのサンプルが用意されています。

関連項目