大規模データとストリーミング

Windows Communication Foundation (WCF) は、XML ベースの通信インフラストラクチャです。 XML データは通常、XML 1.0 仕様で定義された標準テキスト形式でエンコードされるので、接続されたシステムの開発者および設計者にとって共通の関心事は、ネットワーク経由で送信されるメッセージのネットワーク フットプリント (サイズ) です。XML のエンコーディングをテキスト ベースで行う一方で、バイナリ データを効率的に転送することは容易ではありません。

基本的な考慮事項

後で示される WCF の情報に関する背景情報として、接続されたシステムのインフラストラクチャ全般に当てはまる、エンコーディング、バイナリ データ、およびストリーミングに関する一般的な注意点や考慮事項から説明します。

データのエンコーディング : テキストとバイナリ

開発者が揃って口にする懸念には、開始タグと終了タグが繰り返し使用される XML では、バイナリ形式と比較してオーバーヘッドが大きくなるのではないか、数値のエンコーディングは、数値をテキスト値で表現するのでサイズが膨れ上がるのではないか、バイナリ データをテキスト形式に埋め込むためには特別なエンコーディングが必要なので、バイナリ データを効率的に表現することはできないのではないか、などがあります。

このような懸念の多くは当然ではありますが、XML Web サービス環境で XML のテキスト エンコードされたメッセージと、従来のリモート プロシージャ コール (RPC) 環境でバイナリ エンコードされたメッセージとの間の実際の相違は、それほど大きくありません。

XML のテキスト エンコードされたメッセージは、透過的であり、ユーザーが "読める" のに比べ、バイナリ メッセージのほとんどはわかりにくく、ツールなしでデコードすることは困難です。 このような読みやすさの違いから見過ごされる点は、バイナリ メッセージにはペイロードにインライン メタデータも含まれている場合が多く、これによって、XML テキスト メッセージと同様のオーバーヘッドが追加されるという事実です。 これは特に、疎結合および動的呼び出しの実現を目的としたバイナリ形式に当てはまります。

ただし、バイナリ形式では、これらのメタデータ記述情報が "ヘッダー" に格納されるのが普通です。ヘッダーでは、後続のデータ レコードに関するデータ レイアウトも宣言します。 この共通メタデータ ブロック宣言の後に続くペイロードに伴うオーバーヘッドは最小限です。 一方、XML では、各データ項目は要素または属性に囲まれ、外側のメタデータはシリアル化されたペイロード オブジェクトごとに、繰り返し含められます。 これらのことと、一部のメタデータ記述はテキストとバイナリの両方に対して必要になることを考えると、シリアル化するペイロード オブジェクトが 1 つであれば、テキスト表現とバイナリ表現のサイズは同様になることがわかります。ただしバイナリ形式の方が全体のオーバーヘッドが低いため、転送するペイロード オブジェクトの数が増えるごとに、共通のメタデータ記述によるメリットが生じます。

数値など特定のデータ型では、プレーンテキストの代わりに 128 ビットの decimal 型など固定サイズのバイナリ数値表現を使用するデメリットもあります。プレーンテキスト表現を使用すると何バイトか小さくなる可能性があります。 また、テキスト データには、より柔軟性に優れた XML テキスト エンコーディングのオプションから選択できることによるメリットがあります。一方、一部のバイナリ形式では、16 ビットまたは 32 ビットの Unicode が既定値として設定されている場合があります (これは、.NET Binary XML 形式には当てはまりません)。

したがって、テキストかバイナリかを決定する場合、バイナリ メッセージは常に XML テキスト メッセージよりも小さいという推測に基づいて簡単に決めることはできません。

XML テキスト メッセージは、標準ベースのメッセージであるため、きわめて広範囲な相互運用性オプションとプラットフォーム サポートが提供されるという明確な利点があります。 詳細については、このトピックで後述する「エンコーディング」を参照してください。

バイナリ コンテンツ

写真、ビデオ、サウンド クリップのほか、サービスとコンシューマーとの間で交換される他の不透明な形式のバイナリ データなど、サイズの大きいバイナリ データ項目の場合、生成されるメッセージ サイズに関しては、テキスト ベースのエンコーディングよりバイナリ エンコーディングの方が優れています。 このようなデータを XML テキストに格納するには、Base64 エンコーディングを使用してそのデータをエンコードするのが一般的です。

Base64 でエンコードされた文字列では、各文字で元の 8 ビット データのうち 6 ビット分を表すので、その結果、Base64 ではエンコーディングとオーバーヘッドの比率が 4:3 になります。このとき、通常追加される書式設定文字 (復帰とライン フィード) は計算に入れていません。 XML エンコーディングとバイナリ エンコーディングとの間の相違の大きさは、通常、シナリオによって異なりますが、500 MB のペイロードを送信するときにサイズの増加率が 33% を超えることは、受け入れられません。

このようなエンコーディングのオーバーヘッドを回避するには、MTOM (Message Transmission Optimization Mechanism) 規格を使用すると、特別なエンコーディングを行うことなく、メッセージに含まれている大きいデータ要素を外部化し、それをバイナリ データとしてメッセージと共に送信できます。 MTOM でメッセージを交換する方法は、添付ファイルや埋め込みコンテンツ (写真やその他の埋め込みコンテンツ) が付属している簡易メール転送プロトコル (SMTP) 電子メール メッセージを交換する方法と似ています。MTOM メッセージは multipart/related MIME シーケンスとしてパッケージ化され、ルート パートが実際の SOAP メッセージになります。

MTOM SOAP メッセージが、エンコードされていないバージョンと異なるのは、メッセージ内でバイナリ データを含んでいた元の要素の代わりに、それぞれの MIME パートを参照している特別な要素タグが配置される点です。 つまり SOAP メッセージでは、メッセージと共に送信される MIME パートを指すことによってバイナリ コンテンツが参照されますが、含まれているのは XML テキスト データのみです。 このモデルは、広く確立している SMTP モデルに厳密に適合するように作成されています。このため、さまざまなプラットフォームで、MTOM メッセージをエンコードまたはデコードするための幅広いツール サポートが提供され、きわめて高い相互運用性が確保されています。

ただし MTOM でも Base64 の場合と同様、MIME 形式をサポートするためのオーバーヘッドが伴います。このため、MTOM を使用するメリットが現れるのは、バイナリ データ要素のサイズが約 1 KB を超える場合だけです。 バイナリ ペイロードが 1 KB を下回る場合は、このオーバーヘッドが原因で、バイナリ データに Base64 エンコーディングを使用したメッセージよりも、エンコード済みの MTOM メッセージの方が大きくなる可能性があります。 詳細については、このトピックで後述する「エンコーディング」を参照してください。

大規模データ コンテンツ

ネットワーク フットプリントとは別に、前述の例のようにペイロードが 500 MB であれば、サービスとクライアントにもローカルの問題が生じます。 WCF の既定では、メッセージが "バッファー モード" で処理されます。 つまり、メッセージ コンテンツ全体が、送信前にも受信後にもメモリに存在します。 この方式は、ほとんどのシナリオに対して有効であり、デジタル署名や信頼できる配信などのメッセージング機能には必要ですが、メッセージが大きいと、システムのリソースが使い果たされてしまう可能性があります。

ペイロードが大きい場合、有効な処理方法は、ストリーミングです。 メッセージ、特に XML で表現されているメッセージは一般的に、比較的小型のデータ パッケージであると思われがちですが、メッセージのサイズは数ギガバイトになることもあり、データ パッケージというよりも連続したデータ ストリームに似ています。 バッファー モードではなく、ストリーミング モードでデータを転送する場合、送信側が、メッセージ本体のコンテンツをストリームの形で受信側に対して準備します。続いてメッセージ インフラストラクチャは、このデータの準備が整い次第、送信側から受信側にデータを転送します。

このような大きいデータ コンテンツの転送が発生する最も一般的なシナリオは、次のようなバイナリ データ オブジェクトの転送です。

  • 簡単にメッセージ シーケンスに分割できないバイナリ データ オブジェクト

  • タイムリーに配信する必要があるバイナリ データ オブジェクト

  • 転送の開始時に完全な形で準備されていないバイナリ データ オブジェクト

通常、データにこのような制約がない場合は、1 つの大きいメッセージではなく、セッションの有効範囲内でメッセージ シーケンスを送信することをお勧めします。 詳細については、このトピックで後述する「データのストリーミング」を参照してください。

大量のデータを送信する場合は、maxAllowedContentLength の IIS 設定 (詳細については、IIS 要求の制限の構成に関するページを参照してください) および maxReceivedMessageSize のバインディング設定 (System.ServiceModel.BasicHttpBinding.MaxReceivedMessageSizeMaxReceivedMessageSize など) を行う必要があります。 maxAllowedContentLength プロパティの既定値は 28.6 MB で、maxReceivedMessageSize プロパティの既定値は 64 KB です。

エンコーディング

"エンコーディング" とは、ネットワーク上でのメッセージの表示方法に関する一連の規則を定義したものです。 "エンコーダー" はこのようなエンコーディングを実装するもので、送信側では、メモリ内 Message を変換して、ネットワークで送信できるバイト ストリームまたはバイト バッファーにする役割を担います。 受信側では、バイト シーケンスがエンコーダーによってメモリ内メッセージに変換されます。

WCF には、3 つのエンコーダーが用意されています。開発者は、必要に応じて独自のエンコーダーを作成してプラグインすることもできます。

個々の標準バインディングには、構成済みのエンコーダーが含まれています。Net* プレフィックスで始まるバインディングでは、(BinaryMessageEncodingBindingElement クラスを含めることで) バイナリ エンコーダーが使用されるのに対し、BasicHttpBinding クラスと WSHttpBinding クラスでは、既定で (TextMessageEncodingBindingElement クラスを含めることで) テキスト メッセージ エンコーダーが使用されます。

エンコーダー バインド要素 説明
TextMessageEncodingBindingElement テキスト メッセージ エンコーダーは、すべての HTTP ベースのバインディングに対する既定のエンコーダーで、相互運用性が特に重要になるカスタムのバインディングにも適しています。 このエンコーダーで入出力が行われるのは、標準の SOAP 1.1/SOAP 1.2 テキスト メッセージであり、バイナリ データに対して特別な処理は行われません。 メッセージの System.ServiceModel.Channels.MessageVersion プロパティが MessageVersion.None に設定されている場合、出力から SOAP エンベロープ ラッパーが除去され、メッセージ本体のコンテンツだけがシリアル化されます。
MtomMessageEncodingBindingElement MTOM メッセージ エンコーダーは、バイナリ データに対する特別な処理を実装したテキスト エンコーダーです。このエンコーダーは、状況に応じた最適化を要するユーティリティなので、どの標準バインディングでも既定では使用されません。 MTOM エンコーディングのメリットを生じるしきい値より大きいバイナリ データがメッセージにある場合、そのデータは、メッセージ エンベロープの後に続く MIME パートとして外部化されます。 このセクションの「MTOM の有効化」を参照してください。
BinaryMessageEncodingBindingElement バイナリ メッセージ エンコーダーは、Net* バインディングの既定のエンコーダーであり、送信側と受信側の両方が WCF をベースとしている場合にも適しています。 バイナリ メッセージ エンコーダーでは、XML 情報セット (Infoset) を対象とした Microsoft 固有のバイナリ表現である .NET Binary XML 形式が使用されます。この形式ではバイナリ データがバイト ストリームとしてエンコードされ、通常は、同等の XML 1.0 表現よりもフットプリントが小さくなりきます。

相互運用性が要求される通信パスでは一般的にテキスト メッセージ エンコーディングが最適であり、それ以外の通信パスではバイナリ メッセージ エンコーディングが最適です。 バイナリ メッセージ エンコーディングで生成されるメッセージのサイズは、単一のメッセージであればテキストより小さくなることが普通ですが、通信セッションの間に、さらに小さくなっていきます。 テキスト エンコーディングと異なり、バイナリ エンコーディングでは、Base64 を使用するなど、バイナリ データに対する特別な処理を行う必要がありません。このエンコーディングでは、バイトがバイトとして表現されます。

ソリューションで、相互運用性は必要ではないが、HTTP トランスポートを使用する場合は、トランスポートとして BinaryMessageEncodingBindingElement クラスを使用するカスタム バインディングに HttpTransportBindingElement を組み込むことができます。 サービスを利用する多数のクライアントが相互運用性を必要とする場合は、両者にとって適切な種類のトランスポートとエンコーディングがそれぞれに有効化された並行エンドポイントを公開することをお勧めします。

MTOM の有効化

相互運用性が必須である一方で、大きなバイナリ データを送信する必要がある場合、エンコーディング方法のもう 1 つの選択肢に、MTOM メッセージ エンコーディングがあります。このエンコーディングを有効化するには、標準の BasicHttpBinding バインディングまたは WSHttpBinding バインディングでそれぞれの MessageEncoding プロパティを Mtom に設定するか、MtomMessageEncodingBindingElementCustomBinding を組み込みます。 次のコード例は、「MTOM エンコーディング」のサンプルからの抜粋であり、構成で MTOM を有効化する方法を示しています。

<system.serviceModel>  
     …  
    <bindings>  
      <wsHttpBinding>  
        <binding name="ExampleBinding" messageEncoding="Mtom"/>  
      </wsHttpBinding>  
    </bindings>  
     …  
</system.serviceModel>  

前述のように、MTOM エンコーディングの使用が適しているかどうかは、送信するデータ量によって異なります。 また、MTOM はバインディング レベルで有効になるので、MTOM を有効にすると、個々のエンドポイント上のすべての操作に作用します。

MTOM エンコーダーでは、バイナリ データが最終的に外部化されるかどうかに関係なく、MTOM エンコードされた MIME/multipart メッセージが常に出力されるので、通常は、1 KB を超えるバイナリ データを含んだメッセージの交換が行われるエンドポイントに対してのみ、MTOM を有効にしてください。 また、MTOM が有効化されたエンドポイント用に設計されたサービス コントラクトは、可能であれば、このようなデータ転送操作を指定するように制限してください。 関連する制御機能は別のコントラクトに記述するようにしてください。 この "MTOM のみ" の規則が当てはまるのは、MTOM が有効化されたエンドポイントを経由して送信されるメッセージだけです。MTOM 以外の受信メッセージについては、MTOM エンコーダーによって同様にデコードおよび解析されます。

MTOM エンコーダーの使用は、他の WCF 機能すべてに適合しています。 セッション サポートが必要な場合などのように、すべての場合でこの規則が守られるわけではありません。

プログラミング モデル

3 つの組み込みエンコーダーのうち、どのエンコーダーをアプリケーションで使用する場合も、バイナリ データの転送に関するプログラミング方法は同じです。 違いは、WCF による、データ型に基づいたデータ処理の方法です。

[DataContract]  
class MyData  
{  
    [DataMember]  
    byte[] binaryBuffer;  
    [DataMember]  
    string someStringData;  
}

MTOM を使用する場合、上記のデータ コントラクトは次の規則に従ってシリアル化されます。

  • binaryBuffernull ではなく、それぞれに格納されているデータのサイズが大きい場合、つまり Base64 エンコーディングと比較しても MTOM 外部化によるオーバーヘッド (MIME ヘッダーなど) を正当化できるサイズである場合は、データが外部化され、バイナリ MIME パートとしてメッセージと共に転送されます。 しきい値を超えていない場合、データは Base64 としてエンコードされます。

  • メッセージの本体で、文字列 (およびバイナリ以外のその他の型) はサイズに関係なく文字列として表現されます。

上記の例に示したような明示的なデータ コントラクトを使用する場合も、操作にパラメーター リストを使用する場合も、入れ子構造のデータ コントラクトを使用する場合も、コレクション内でデータ コントラクト オブジェクトを転送する場合も、MTOM エンコーディングへの作用は同じです。 バイト配列は、常に最適化の対象と見なされるため、最適化のしきい値条件を満たしていれば最適化されます。

Note

データ コントラクト内では System.IO.Stream の派生型を使用しないでください。 ストリーム データは、次の「データのストリーミング」で説明するストリーミング モデルを使用して送受信する必要があります。

データのストリーミング

大量のデータを転送する場合、メッセージ全体をメモリ内でバッファー化および処理するという既定動作の代わりに、WCF のストリーミング転送モードを使用することができます。

前述のように、ストリーミングの有効化は、データをセグメントに分割できない場合、メッセージをタイムリーに配信する必要がある場合、または転送の開始時にデータがすべて揃っていない場合に、テキストまたはバイナリのコンテンツを伴う大きなメッセージに関してのみ実行するようにしてください。

制限

ストリーミングを有効化した状態では、WCF の多くの機能を使用できません。

  • メッセージ本体に対するデジタル署名は実行できません。デジタル署名では、メッセージ コンテンツ全体に対してハッシュを計算する必要があります。 ところがストリーミングでは、メッセージ ヘッダーが作成され、送信される時点では、メッセージ コンテンツがすべて揃っているわけではありません。デジタル署名を処理できないのは、このためです。

  • 暗号化では、データが正しく再構築されていることを検証するために、デジタル署名が必要になります。

  • 信頼できるセッションでは、メッセージが転送中に失われた場合に再配信できるように、クライアントで送信メッセージをバッファー化する必要があります。また、サービス実装にメッセージを渡す前に、いったんメッセージをサービスで格納し、メッセージが正しい順序で受信されなかった場合に備えてメッセージの順序を保持する必要があります。

このような機能上の制約により、ストリーミングではトランスポート レベルのセキュリティ オプションしか使用できず、信頼できるセッションを有効にできません。 ストリーミングは、以下のシステム定義バインディングでしか使用できません。

HTTP とは異なり、NetTcpBindingNetNamedPipeBinding の基になるトランスポートには、信頼できる配信と接続ベースのセッション サポートが備わっているので、これら 2 つのバインディングが上記の制約から受ける影響はわずかです。

ストリーミングは、メッセージ キュー (MSMQ) トランスポートでは利用できないため、NetMsmqBinding クラスまたは MsmqIntegrationBinding クラスと共に使用することはできません。 メッセージ キュー トランスポートでは、メッセージ サイズを制限したバッファー化によるデータ転送だけがサポートされています。これに対し他のトランスポートでは、ほとんどのシナリオにおいてメッセージ サイズの実質的な制限はありません。

ストリーミングは、ピア チャネル トランスポートを使用している場合も利用できないため、NetPeerTcpBinding と共に使用することはできません。

ストリーミングとセッション

セッション ベースのバインディングでストリーミングを呼び出すと、予期しない動作を引き起こすことがあります。 すべてのストリーミング呼び出しは単一のチャネル (データグラム チャネル) を通じて行われますが、このチャネルは使用されるバインディングがセッションを使用するように構成されている場合であっても、セッションをサポートしません。 セッション ベースのバインディングによって複数のクライアントが同一のサービス オブジェクトに対してストリーミング呼び出しを行う場合、このサービス オブジェクトのコンカレンシー モードが単一に設定され、インスタンス コンテキスト モードが PerSession に設定されていると、すべての呼び出しがこのデータグラム チャネルを通過する必要があるため、同時に処理される呼び出しは 1 つに限られることになります。 そのため、1 つ以上のクライアントがタイムアウトとなる可能性があります。サービス オブジェクトのインスタンス コンテキスト モードを呼び出しごと (PerCall) に設定するか、またはコンカレンシー モードを複数に設定することで、この問題を回避できます。

Note

この場合、利用可能になる "セッション" は 1 つしかないため、MaxConcurrentSessions は効力を失います。

ストリーミングの有効化

ストリーミングは次の方法で有効にできます。

  • ストリーミング モードで要求の送信および受け入れを行い、バッファー モードで応答の受け入れおよび返信を行う (StreamedRequest)。

  • バッファー モードで要求の送信および受け入れを行い、ストリーミング モードで応答の受け入れおよび返信を行う (StreamedResponse)。

  • 両方向の要求および応答をストリーミング モードで送受信する (Streamed)。

ストリーミングを無効化するには、転送モードを Buffered (すべてのバインディングでの既定の設定) に設定します。 構成で転送モードを設定する方法を次のコードに示します。

<system.serviceModel>  
     …  
    <bindings>  
      <basicHttpBinding>  
        <binding name="ExampleBinding" transferMode="Streamed"/>  
      </basicHttpBinding>  
    </bindings>  
     …  
</system.serviceModel>  

コード内でバインディングをインスタンス化するときは、そのバインディングの TransferMode プロパティ (またはカスタム バインドを作成している場合は、トランスポート バインド要素) をそれぞれ上記の値のいずれかに設定する必要があります。

送信側と受信側で別々に、要求または応答あるいは両方向に対してストリーミングを有効化しても、機能には影響しません。 ただし、転送されるデータのサイズが大きくて、ストリーミングを有効化することが双方にとってのメリットになるかどうかを常に前提として判断する必要があります。 一方のエンドポイントに WCF が実装されていないようなクロス プラットフォームの通信の場合、ストリーミングが使用できるかどうかは、そのプラットフォームのストリーミング機能に依存します。 もう 1 つのまれな例外は、クライアントまたはサービスが作業セットを最小限に抑える必要があり、使用できるバッファー サイズが制限されるような、メモリ消費重視のシナリオです。

非同期ストリーミングの有効化

非同期ストリーミングを有効にするには、エンドポイントの DispatcherSynchronizationBehavior 動作をサービス ホストに追加し、その AsynchronousSendEnabled プロパティを true に設定します。 送信側に実際の非同期ストリーミング機能も追加されています。 これによって、複数のクライアントにメッセージをストリーム出力するシナリオで、一部のクライアントがネットワークの混雑により読み取りが遅いか、読み取りをまったく行っていない場合に、サービスのスケーラビリティが向上します。 このようなシナリオでは、クライアントごとのサービスの個別のスレッドがブロックされないようになりました。 サービスはこれによってこれまで以上のクライアントを処理できるようになり、スケーラビリティが向上します。

ストリーミング転送のプログラミング モデル

ストリーミングのプログラミング モデルは単純です。 ストリーム化されたデータを受信するには、Stream 型の入力パラメーターを 1 つ使用する操作コントラクトを指定します。 ストリーム化されたデータを返信するには、Stream 参照を返します。

[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]  
public interface IStreamedService  
{  
    [OperationContract]  
    Stream Echo(Stream data);  
    [OperationContract]  
    Stream RequestInfo(string query);  
    [OperationContract(OneWay=true)]  
    void ProvideInfo(Stream data);  
}  

上記の例で操作 Echo は、ストリームの受信および返信を行うので、Streamed が設定されたバインディングで使用する必要があります。 RequestInfo 操作の場合、StreamedResponse だけを返すので、Stream が最も適しています。 一方向操作は、StreamedRequest に最適です。

次の Echo 操作または ProvideInfo 操作に 2 つ目のパラメーターを追加すると、サービス モデルはバッファー モードに戻り、ストリームの実行時シリアル化表現が使用されます。 エンドツーエンドの要求ストリーミングとの互換性があるのは、単一の入力ストリーム パラメーターを使用する操作だけです。

この規則は、メッセージ コントラクトにも同様に適用されます。 次の例に示すように、メッセージ コントラクトには、ストリームであるメッセージ本体メンバーを 1 つだけ指定できます。 ストリームと共に他の追加情報も転送する場合、追加情報はメッセージ ヘッダーに入れる必要があります。 メッセージ本体は、ストリーム コンテンツ専用として予約されています。

[MessageContract]  
public class UploadStreamMessage  
{  
   [MessageHeader]  
   public string appRef;  
   [MessageBodyMember]  
   public Stream data;  
}

ストリームがファイルの末尾 (EOF) に達すると、ストリーミング転送は終了し、メッセージが閉じられます。 値を返したり操作を呼び出したりするためにメッセージを送信する際には、FileStream を渡すことができます。すると、WCF インフラストラクチャにより、ストリームの読み出しが完了して EOF に達するまで、ストリームのデータがすべて獲得されます。 ストリーム化されたデータを転送する際に、このような Stream のビルド済み派生クラスがそのデータのソースに存在しない場合は、対応するクラスを作成し、そのクラスでストリーム ソースを覆ったうえで、これを引数または戻り値として使用する必要があります。

メッセージを受信したとき、WCF では、Base64 でエンコードされたメッセージ本体のコンテンツ (MTOM が使用されていれば各 MIME パート) についてストリームが作成されます。コンテンツの読み取りが完了した時点でストリームは EOF に達します。

トランスポート レベルのストリーミングは、その他のメッセージ コントラクト型 (パラメーター リスト、データ コントラクトの引数、明示的なメッセージ コントラクト) でも使用できますが、このような型指定メッセージのシリアル化および逆シリアル化には、シリアライザーによるバッファー化が必要なので、これらの使用は適切ではありません。

大規模データに関するセキュリティの考慮事項

すべてのバインディングで、受信メッセージのサイズを制限して、サービス拒否攻撃を防止できます。 たとえば、BasicHttpBinding では、受信メッセージのサイズを制限し、メッセージの処理時にアクセスされるメモリの最大容量も制限する System.ServiceModel.BasicHttpBinding.MaxReceivedMessageSize プロパティが公開されます。 この単位はバイトで設定されます。既定値は 65,536 バイトです。

大きなデータのストリーミングを行うシナリオに特有のセキュリティの脅威は、受信側が、データがストリーミングされることを想定しているときに、データをバッファーさせることで、サービス拒否が誘発されることです。 たとえば、WCF ではメッセージの SOAP ヘッダーが常にバッファーされるため、攻撃者は、すべてがヘッダーで構成されている悪意のある大きなメッセージを作成して、データを強制的にバッファーすることができます。 ストリーミングが有効になっている場合は、MaxReceivedMessageSize を極端に大きい値に設定できます。これは、受信側が、一度にメッセージ全体をメモリにバッファーすることを想定していないためです。 メッセージをバッファーするように WCF に強制している場合は、メモリのオーバーフローが発生します。

そのため、この場合は、受信メッセージの最大サイズを制限するだけでは不十分です。 WCF によってバッファーされるメモリを制限するには、MaxBufferSize プロパティが必要です。 ストリーミングを使用する場合は、これを安全な値に設定する (または既定値のままにしておく) ことが重要です。 たとえば、サービスでは、サイズが 4 GB までのファイルを受信し、それをローカル ディスクに格納する必要があるとします。 また、一度に 64 KB のデータしかバッファーできないようにメモリが制限されているとします。 その場合、MaxReceivedMessageSize を 4 GB、MaxBufferSize を 64 KB に設定します。 また、サービス実装において、64 KB ずつ受信ストリームから読み取り、前のデータがディスクに書き込まれ、メモリから破棄されるまで次のデータを読み取らないようにする必要があります。

このクォータは、WCF によって行われるバッファーリングのみを制限するものであり、独自のサービスまたはクライアント実装で行うバッファーリングからは保護できないことを理解しておくことも重要です。 セキュリティについてのその他の考慮事項の詳細については、「セキュリティに関するデータの考慮事項」を参照してください。

Note

バッファー転送とストリーミング転送のどちらを使用するかは、エンドポイントごとにローカルに決定します。 HTTP トランスポートの場合、転送モードは、接続、つまりプロキシ サーバーなどの中継局に伝達されません。 転送モードの設定は、サービス インターフェイスの記述に反映されません。 サービスに対して WCF クライアントを生成した後、ストリーミング転送で使用する予定のサービスの構成ファイルを編集し、モードを設定する必要があります。 TCP トランスポートと名前付きパイプ トランスポートの場合、転送モードはポリシー アサーションとして伝達されます。

関連項目