WCF サービスを呼び出した際に 「受信メッセージの最大メッセージ サイズ クォータ (65536) を超えました」 というエラーが発生するケースは、業務システム連携の現場で非常に多く見られます。小さなレスポンスでは問題なく動作するのに、データ件数が増えた途端にチャネルが Fault 状態になり、通信が停止します。
この記事では、エラーの原因を正しく理解し、クライアント側・サーバー側の両方で設定を修正する方法を詳しく解説します。
エラーの意味
例外の全文は以下のような内容です。
System.ServiceModel.CommunicationException:
The maximum message size quota for incoming messages (65536) has been exceeded.
To increase the quota, use the MaxReceivedMessageSize property on the appropriate binding element.
WCF はすべてのバインディングに対して、受信メッセージのデフォルト上限を 65,536 バイト (64 KB) に設定しています。これはセキュリティ対策として意図的に低く設定された値で、悪意あるサービスからの大量データによるメモリ枯渇を防ぐ目的があります。
ポイントは「受信 (incoming)」という点です。クライアント側では「受信」= サーバーからのレスポンスを意味し、サーバー側では「受信」= クライアントからのリクエストを意味します。どちら側でメッセージサイズを超過しているかを正確に把握する必要があります。
解決策 1: クライアント側の MaxReceivedMessageSize を増やす
最も一般的なケースは、クライアントが大きなレスポンスを受信する場面です。app.config または web.config のバインディング設定を確認します。
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="LargeMessageBinding"
maxReceivedMessageSize="10485760"
maxBufferSize="10485760">
<readerQuotas maxDepth="64"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="4096"
maxNameTableCharCount="16384" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://example.com/MyService.svc"
binding="basicHttpBinding"
bindingConfiguration="LargeMessageBinding"
contract="IMyService" />
</client>
</system.serviceModel>
主要なプロパティは以下のとおりです。
maxReceivedMessageSize— 受信メッセージの最大バイト数。10485760で 10 MB まで許可されます。maxBufferSize— Buffered 転送モード (デフォルト) ではmaxReceivedMessageSizeと同じ値に設定する必要があります。値が異なるとArgumentExceptionが発生します。readerQuotas— XML リーダーの制限値。大きなレスポンスではmaxStringContentLengthやmaxArrayLengthの上限にも到達する場合があります。
よくある失敗: bindingConfiguration 名の不一致
「設定を変更したのにエラーが解消しない」という場合、endpoint の bindingConfiguration 属性と binding の name 属性が一致していないことが原因であるケースが多いです。WCF はこの不一致をエラーとせず、デフォルト値 (64 KB) にフォールバックします。大文字小文字を含めて完全一致しているか確認してください。
解決策 2: サーバー側の MaxReceivedMessageSize を増やす
クライアントが大きなリクエストを送信するケース (ファイルアップロードや一括データ投入など) では、サーバー側のバインディングも設定が必要です。
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="LargeRequestBinding"
maxReceivedMessageSize="10485760"
maxBufferSize="10485760">
<readerQuotas maxDepth="64"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="4096"
maxNameTableCharCount="16384" />
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="MyNamespace.MyService">
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="LargeRequestBinding"
contract="MyNamespace.IMyService" />
</service>
</services>
</system.serviceModel>
サーバーの設定変更後は、サービスの再起動または IIS アプリケーションプールのリサイクルが必要です。
解決策 3: バインディング別の設定
WCF のバインディングの種類によって設定方法が異なります。
wsHttpBinding
<wsHttpBinding>
<binding name="LargeWsHttp"
maxReceivedMessageSize="10485760"
maxBufferPoolSize="10485760">
<readerQuotas maxStringContentLength="2147483647"
maxArrayLength="2147483647" />
</binding>
</wsHttpBinding>
wsHttpBinding には maxBufferSize プロパティがありません。代わりに maxBufferPoolSize でバッファプールのサイズを制御します。
netTcpBinding
<netTcpBinding>
<binding name="LargeNetTcp"
maxReceivedMessageSize="10485760"
maxBufferSize="10485760"
maxBufferPoolSize="10485760">
<readerQuotas maxStringContentLength="2147483647"
maxArrayLength="2147483647" />
</binding>
</netTcpBinding>
customBinding
カスタムバインディングの場合は、transport バインディング要素に制限値を設定します。
<customBinding>
<binding name="LargeCustom">
<textMessageEncoding messageVersion="Soap11" />
<httpTransport maxReceivedMessageSize="10485760"
maxBufferSize="10485760" />
</binding>
</customBinding>
解決策 4: ストリーミング転送モードの活用
メッセージサイズが数十 MB を超える場合、全体をメモリにバッファリングするのはコストが高くなります。WCF の Streamed 転送モード を使うと、メッセージ全体をメモリに展開せずストリームとして処理できます。
<basicHttpBinding>
<binding name="StreamedBinding"
transferMode="Streamed"
maxReceivedMessageSize="104857600">
<readerQuotas maxStringContentLength="2147483647" />
</binding>
</basicHttpBinding>
transferMode の設定値は以下の 4 種類です。
| 値 | リクエスト | レスポンス |
|---|---|---|
Buffered (デフォルト) | バッファリング | バッファリング |
Streamed | ストリーミング | ストリーミング |
StreamedRequest | ストリーミング | バッファリング |
StreamedResponse | バッファリング | ストリーミング |
ストリーミングモードの制約事項:
- サービス操作は
StreamまたはMessage型のパラメータを使用する必要があります。任意の複合型をストリーミングすることはできません。 - ストリーミングモードの
maxBufferSizeは SOAP ヘッダーのバッファサイズのみを制御するため、小さな値 (65536 など) のまま維持します。 - Reliable Session やトランスポートレベルのセキュリティに制限があります。
解決策 5: コードによるプログラマティック設定
構成ファイルを使わずコードで WCF クライアントを作成する場合は、バインディングプロパティを直接設定します。
var binding = new BasicHttpBinding();
binding.MaxReceivedMessageSize = 10 * 1024 * 1024; // 10 MB
binding.MaxBufferSize = 10 * 1024 * 1024;
binding.ReaderQuotas.MaxStringContentLength = int.MaxValue;
binding.ReaderQuotas.MaxArrayLength = int.MaxValue;
var endpoint = new EndpointAddress("http://example.com/MyService.svc");
var client = new MyServiceClient(binding, endpoint);
この方法は、テスト環境や実行時にペイロードサイズに応じて制限値を調整する場合に便利です。
診断手順
設定を変更してもエラーが解消しない場合は、以下のチェックリストを確認してください。
-
正しい構成ファイルが読み込まれているか確認する。 コンソールアプリは
app.config、Web アプリはweb.configを使用します。クラスライブラリに独自の config がある場合でも、ホストアプリケーションの config のみが有効です。 -
バインディング構成名が一致しているか確認する。
bindingConfigurationとbindingのnameを大文字小文字を含めて比較してください。 -
クライアントとサーバーの両方を確認する。 両方を管理している場合は、双方に適切な制限値を設定してください。
-
WCF トレースを有効にして 実際のメッセージサイズを確認する。
<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Warning">
<listeners>
<add name="traceListener"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="c:\logs\wcf-trace.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
- 実際のレスポンスサイズを計測する。 Fiddler や Wireshark でレスポンスサイズを確認してください。冗長な XML シリアライゼーションや Base64 エンコードされたバイナリデータにより、想定以上にサイズが大きくなっている場合があります。
セキュリティ上の注意
本番環境で maxReceivedMessageSize を int.MaxValue (約 2 GB) に設定するのは避けてください。デフォルトの制限値が提供する DoS 攻撃対策が無効になります。代わりに以下のアプローチを推奨します。
- 各オペレーションの現実的な最大レスポンスサイズを見積もる
- 想定最大値の 2 倍から 5 倍の余裕を持たせる
- 制限値を上げた後、負荷テスト時のメモリ使用量を監視する
- 本当に大きなペイロードにはバッファ制限を上げるのではなくストリーミング転送モードを使用する
SOAPless による解決
WCF のメッセージサイズクォータの対応は、XML 構成ファイルの編集、バインディング名の照合、設定変更のたびのデプロイといった手間がかかります。モダンなアプリケーションから SOAP サービスを利用している場合、この複雑さを維持し続ける価値があるか検討する余地があります。
SOAPless は任意の WSDL ベースの SOAP サービスを REST JSON API に変換します。WSDL URL を貼り付けるだけで RESTful エンドポイントが自動生成され、大きなレスポンスもバインディング設定やバッファサイズの調整なしで透過的に処理されます。認証情報はダッシュボードで暗号化管理され、OpenAPI 仕様が自動生成されるため、任意の HTTP クライアントからすぐに利用できます。
WCF の設定に費やす時間がビジネスロジックの実装時間を上回っているなら、SOAPless を試してみてください。