WCF: Request failing when data pulled in stream is big

Problem Definition:

I have a WCF service "" built on .Net Framework 4.0 and hosted on IIS over a windows server 2008 R2 box. I am pulling data from database using this service. I am encountering with error

"System.ServiceModel.CommunicationException, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”. "The underlying connection was closed: The connection was closed unexpectedly

I see this problem when data being pulled is more the 4 MB as disc size. As data is transmitted into serialized form so this size actually not the size of the stream instead this is the size of the data when saved into the disc. 

It is also validated that no bad data is transmitted and issue appears whenever the row count pulled from the database is high. 

Analysis:  

For any WCF related issue if the issue can be reproduced on demand, I will strongly recommend to collect verbose level trace as that will collect detailed information about the issue. So here I collected WCF verbose trace and verbose level trace give me information that connection is being closed by the server as shown in exception.

System.ServiceModel.CommunicationException: The underlying connection was closed: The connection was closed unexpectedly. ---> System.Net.WebException: The underlying connection was closed: The connection was closed unexpectedly.

 

  

 

 

From this exception I got a clue that server is closing the connection but why and after how much time? 

So I will go ahead and collect following data in parallel. 

1-      Client side WCF + System.Net trace

2-      Server side WCF + System.Net trace 

Below are the settings to enable System.Net and WCF tracing:

 

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

  <system.diagnostics>

    <sources>                                      

      <source name="System.ServiceModel" switchValue="Verbose, ActivityTracing" propagateActivity="true" >

        <listeners>

          <add name="xml"/>

        </listeners>

      </source>

      <source name="System.ServiceModel.MessageLogging">

        <listeners>

          <add name="xml"/>

        </listeners>

      </source>

      <source name="System.Net">

        <listeners>

          <add name="System.Net"/>

        </listeners>

      </source>

      <source name="System.Net.HttpListener">

        <listeners>

          <add name="System.Net"/>

        </listeners>

      </source>

      <source name="System.Net.Sockets">

        <listeners>

          <add name="System.Net"/>

        </listeners>

      </source>

      <source name="System.Net.Cache">

        <listeners>

          <add name="System.Net"/>

        </listeners>

      </source>

    </sources>

    <sharedListeners>

      <add name="xml"

               type="System.Diagnostics.XmlWriterTraceListener"

                     initializeData="C:\temp\WCFTraces.svclog" />

      <add name="System.Net" type="System.Diagnostics.TextWriterTraceListener"

      initializeData="c:\temp\SNtrace.log" traceOutputOptions = "DateTime" />

    </sharedListeners>

    <switches>

      <add name="System.Net" value="Verbose" />

      <add name="System.Net.Sockets" value="Verbose" />

      <add name="System.Net.Cache" value="Verbose" />

      <add name="System.Net.HttpListener" value="Verbose" />

    </switches>

  </system.diagnostics>

  <system.serviceModel>

    <diagnostics>

      <messageLogging logEntireMessage="true" logMalformedMessages="true"

          logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true" />

    </diagnostics>

  </system.serviceModel>

</configuration>  

 

From the client side System.Net traces I searched for the exceptions and got following exceptions:

  

 

Which on expanding will show following details:

 

System.Net.Sockets Verbose: 0 : [5220] Socket#59148624::Receive()

    DateTime=2015-04-23T13:42:56.8466796Z

System.Net.Sockets Verbose: 0 : [5220] Data from Socket#59148624::Receive

    DateTime=2015-04-23T13:42:57.5185546Z

System.Net.Sockets Verbose: 0 : [5220] 00000000 : :

    DateTime=2015-04-23T13:42:57.5185546Z

System.Net.Sockets Verbose: 0 : [5220] Exiting Socket#59148624::Receive() -> 0#0

    DateTime=2015-04-23T13:42:57.5185546Z

System.Net.Sockets Verbose: 0 : [5220] Socket#59148624::Dispose()

    DateTime=2015-04-23T13:42:57.5341796Z

System.Net Error: 0 : [5220] Exception in the HttpWebRequest#37711682:: - The underlying connection was closed: The connection was closed unexpectedly.

    DateTime=2015-04-23T13:42:57.5341796Z

System.Net Error: 0 : [5220] Exception in the HttpWebRequest#37711682::GetResponse - The underlying connection was closed: The connection was closed unexpectedly.

 

This means that the exception is recorded when the response was being received by the client and 0 bytes transferred as highlighted.

 Now why this happened?

Let’s trace the service side WCF traces with the timestamp of the System.Net trace. From the timestamp, following exception is of our interest:

  

 

Let’s see the error message of the exception:

 

There was an error while trying to serialize parameter tempuri.org/:GetMarketingInfosResult. The InnerException message was 'Maximum number of items that can be serialized or deserialized in an object graph is '65536'. Change the object graph or increase the MaxItemsInObjectGraph quota. '. Please see InnerException for more details.

 

So is seems this MaxItemsInObjectGraph quotavalue is hitting the limit set by WCF service. Now we need to check this value in the web.config of the service. I am using wsHttpBinding.

But I have not set this value anywhere in my web.config, so it should be taking the default value and what is this default value?

 

We see that this default value is set to 2147483647 Bytes for service behaviors as well as for EndPointBehavious.

 

 

 

 So by some reason this default value is not available so this issue is appearing.

Let’s fix this

Solution:

<behaviors>
<serviceBehaviors>
<behavior name="LargeServiceBehavior">
<dataContractSerializer maxItemsInObjectGraph="100000"/>
</behavior>
</serviceBehaviors>
</behaviors>

And

<behaviors>
<endpointBehaviors>
<behavior name="LargeEndpointBehavior">
<dataContractSerializer maxItemsInObjectGraph="100000"/>
</behavior>
</endpointBehaviors>
</behaviors>

You add these in the <system.serviceModel> element. Don’t forget to set the "behaviorConfiguration" attribute in the configuration of your service or endpoint. And we are done.

Ashutosh Tripathi(MSFT)

Microsoft India