c#とWCFでプロセス間通信をするためにNetTcpBindingを使って通信を行っていたら以下のメッセージが出力され通信エラーとなりました。
System.ServiceModel.CommunicationException: ソケット接続が中止されました。これは、メッセージ処理時のエラー、リモート ホストでの受信タイムアウトの超過、または基になるネットワーク リソースの問題が原因で発生する可能性があります。ローカル ソケットのタイムアウトは '00:01:00' でした。 ---> System.Net.Sockets.SocketException: 既存の接続はリモート ホストに強制的に切断されました。
で、この原因なんですが
DataContractSerializer.MaxItemsInObjectGraph
の制限に引っかかって通信が切断されたのが原因でした。
ただ、MSDNの説明に
プロパティ値
Type: System.Int32
シリアル化または逆シリアル化する項目の最大数。既定値は、MaxValue です。
とあり、最大値が「2,147, 483,647」(21億)と記述があるのですが、この記述のままではなく、設定しないと(たぶん)65,535となっています。このため、リストにオブジェクトを入れて送信すると割とすぐにエラーが発生します。
修正方法
定義ファイルをツールから修正する
定義ファイルの場合、WCFサービス構成エディタで定義ファイルを開いてツリーから
詳細設定 > サービス動作 > MyBehavior を選択し(無い場合作成して)
画面中央の[追加]を指定して
dataContractSerializerを追加し、設定値の、MaxItemsInObjectGraphへ任意の大きい隊を入力します。
定義ファイルを手で修正する
app.config内のビヘイビアへ以下を追記します。
</system.serviceModel> <behaviors> <serviceBehaviors> <behavior name="MyBehavior"> <dataContractSerializer maxItemsInObjectGraph="1073741824" /> ★これを追加 </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>
behaviorノード自体が無いときはノードごと追加します。
この場合、bindingへノードの参照を追加しないといけないのですがここでは割愛します。(というかツール使ってください)
c#コード上で修正する
ServiceHostを宣言している箇所で以下コードを記述します。
// サービスの宣言(適当) var service = new ServiceHost(myType); // ビヘイビアの構成定義に当たるオブジェクトを取得 var config = this.service.Description.Behaviors.Find<ServiceBehaviorAttribute>(); // 取れない場合新規追加 if (config == null) { config = new ServiceBehaviorAttribute() { MaxItemsInObjectGraph = int.MaxValue } } // 任意の大きな値を設定 serviceBehaviorAttribute.MaxItemsInObjectGraph = int.MaxValue;
さいごに
ってかオブジェクトの初期値がint.MaxValueってだけでWCFはあとから値を上書きしてるっぽいですね。
MSDN見て安心してたけどこういう事もあるんですね。テスト重要。