传输更大的结果集时发生WCF CommunicationException

时间:2015-08-04 09:28:42

标签: c# .net wcf

通过WCF WebService访问数据库时,会发生以下错误:An error (Unable to read data from the transport connection: The connection was closed.) occurred while transmitting data over the HTTP channel.

我使用以下测试用例重现错误。

[TestCase]
public void TestLargeDBs()
{
    var cl = new DBUpdaterClient();
    var d1 = cl.ExecuteReaderUGV("test", "SELECT * from tblPerson LIMIT 10000");
    d1 = cl.ExecuteReaderUGV("test", "SELECT * from tblPerson");
    d1 = cl.ExecuteReaderUGV("test", "SELECT * from angebotdetails");
}

第一个结果包含10k行,第二个结果包含20k,第三个结果包含225k。错误可以在任何呼叫时发生,但有时它根本不会发生。起初我以为它与消息长度有关,但现在我不知道问题是什么...有人给我一些提示吗?

虽然文件存在并且配置正确,但跟踪不会产生任何输出我认为......

的Web.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.diagnostics>
    <sources>
      <source name="System.ServiceModel"
              switchValue="Information, ActivityTracing"
              propagateActivity="true" >
        <listeners>
          <add name="xml" 
               type="System.Diagnostics.XmlWriterTraceListener"
               initializeData="nochwas.svclog"/>
        </listeners>
      </source>
      <source name="System.ServiceModel.MessageLogging">
        <listeners>
          <add name="messagelistener"
               type="System.Diagnostics.XmlWriterTraceListener"
               initializeData="myMessages.svclog"></add>
        </listeners>
      </source>
      <source name="myUserTraceSource"
              switchValue="Information, ActivityTracing">
        <listeners>
          <add name="xml" 
               type="System.Diagnostics.XmlWriterTraceListener"
               initializeData="myActivities.svclog"/>
        </listeners>
      </source>
    </sources>
    <trace autoflush="true" />
    <sharedListeners>
      <add name="xml"
           type="System.Diagnostics.XmlWriterTraceListener"
           initializeData="Error.svclog" />
    </sharedListeners>
  </system.diagnostics>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" maxRequestLength="2147483647" executionTimeout="60"/>
  </system.web>
  <system.serviceModel>
    <diagnostics>
      <messageLogging logEntireMessage="true"
                      logMessagesAtServiceLevel="false"
                      logMessagesAtTransportLevel="false"
                      logMalformedMessages="true"
                      maxMessagesToLog="5000"
                      maxSizeOfMessageToLog="2000">
      </messageLogging>
    </diagnostics>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- Legen Sie die Werte unten vor der Bereitstellung auf "false" fest, um die Veröffentlichung von Metadateninformationen zu vermeiden. -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <!-- Damit in Fehlern Ausnahmedetails zum Debuggen angezeigt werden, legen Sie den Wert unten auf "true" fest. Legen Sie ihn vor der Bereitstellung auf "false" fest, um die Veröffentlichung von Ausnahmeinformationen zu vermeiden. -->
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <!-- Umgeht eine CommunicationException, die auftritt, wenn der ObjectGraph überläuft -->
          <dataContractSerializer maxItemsInObjectGraph="2147483646"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IDBUpdater"
                 closeTimeout="00:10:00"
                 openTimeout="00:10:00"
                 receiveTimeout="00:10:00"
                 sendTimeout="00:10:00"
                 maxBufferSize="2147483647"
                 maxBufferPoolSize="2147483647"
                 maxReceivedMessageSize="2147483647"
                 allowCookies="false"
                 bypassProxyOnLocal="false"
                 hostNameComparisonMode="StrongWildcard"
                 messageEncoding="Text"
                 textEncoding="utf-8"
                 transferMode="StreamedResponse"
                 useDefaultWebProxy="true">
          <readerQuotas maxDepth="2147483647"
                        maxStringContentLength="2147483647"
                        maxArrayLength="2147483647"
                        maxBytesPerRead="2147483647"
                        maxNameTableCharCount="2147483647" />
        </binding>
      </basicHttpBinding>
    </bindings>
    <protocolMapping>
      <remove scheme="http" />
      <add scheme="http" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IDBUpdater" />
    </protocolMapping>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="2147483647" />
      </requestFiltering>
    </security>
    <modules runAllManagedModulesForAllRequests="true"/>
    <!--
    Um das Stammverzeichnis der Webanwendung beim Debuggen auszuwählen, legen Sie den Wert unten auf "true" fest.
    Legen Sie ihn vor der Bereitstellung auf "false" fest, um die Veröffentlichung von Informationen über den Webanwendungsordner zu vermeiden.
  -->
    <directoryBrowse enabled="true"/>
  </system.webServer>
</configuration>

的app.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IDBUpdater"
                 closeTimeout="00:10:00"
                 openTimeout="00:10:00"
                 receiveTimeout="00:10:00"
                 sendTimeout="00:10:00"
                 maxBufferSize="2147483647"
                 maxBufferPoolSize="2147483647"
                 maxReceivedMessageSize="2147483647"
                 allowCookies="false"
                 bypassProxyOnLocal="false"
                 hostNameComparisonMode="StrongWildcard"
                 messageEncoding="Text"
                 textEncoding="utf-8"
                 transferMode="StreamedResponse"
                 useDefaultWebProxy="true">
          <readerQuotas maxDepth="2147483647"
                    maxStringContentLength="2147483647"
                    maxArrayLength="2147483647"
                    maxBytesPerRead="2147483647"
                    maxNameTableCharCount="2147483647" />
        </binding>
      </basicHttpBinding>
    </bindings>

    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- Legen Sie die Werte unten vor der Bereitstellung auf "false" fest, um die Veröffentlichung von Metadateninformationen zu vermeiden. -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <!-- Damit in Fehlern Ausnahmedetails zum Debuggen angezeigt werden, legen Sie den Wert unten auf "true" fest. Legen Sie ihn vor der Bereitstellung auf "false" fest, um die Veröffentlichung von Ausnahmeinformationen zu vermeiden. -->
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <!-- Umgeht eine CommunicationException, die auftritt, wenn der ObjectGraph überläuft -->
          <dataContractSerializer maxItemsInObjectGraph="2147483646"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>

    <client>
      <endpoint address="http://10.1.58.48/DBUpdate/UpdateService.svc"
    binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IDBUpdater"
    contract="DBUpdater.IDBUpdater" />
    </client>
  </system.serviceModel>
  <system.data>
    <DbProviderFactories>
      <remove invariant="MySql.Data.MySqlClient" />
      <add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.9.6.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
    </DbProviderFactories>
  </system.data>
</configuration>

我几乎可以通过WebServices阅读有关CommunicationExceptions的所有内容,但是我无法让WebService以可靠的方式工作而不会崩溃。我感谢你们的任何建议!

来自客户端的异常详情:

An error (Unable to read data from the transport connection: The connection was closed.) occurred while transmitting data over the HTTP channel. (CommunicationException (IOException))

bei System.ServiceModel.Channels.HttpInput.WebResponseHttpInput.WebResponseInputStream.Read(Byte[] buffer, Int32 offset, Int32 count)
   bei System.ServiceModel.Channels.MaxMessageSizeStream.Read(Byte[] buffer, Int32 offset, Int32 count)
   bei System.IO.BufferedStream.Read(Byte[] array, Int32 offset, Int32 count)
   bei System.Xml.EncodingStreamWrapper.Read(Byte[] buffer, Int32 offset, Int32 count)
   bei System.Xml.XmlBufferReader.TryEnsureBytes(Int32 count)
   bei System.Xml.XmlBufferReader.GetBuffer(Int32 count, Int32&amp; offset, Int32&amp; offsetMax)
   bei System.Xml.XmlUTF8TextReader.ReadText(Boolean hasLeadingByteOf0xEF)
   bei System.Xml.XmlUTF8TextReader.Read()
   bei System.Runtime.Serialization.XmlSerializableReader.Read()
   bei System.Data.DataTextReader.Read()
   bei System.Data.XmlDataLoader.LoadColumn(DataColumn column, Object[] foundColumns)
   bei System.Data.XmlDataLoader.LoadTable(DataTable table, Boolean isNested)
   bei System.Data.XmlDataLoader.LoadData(XmlReader reader)
   bei System.Data.DataTable.ReadXmlDiffgram(XmlReader reader)
   bei System.Data.DataTable.ReadXml(XmlReader reader, XmlReadMode mode, Boolean denyResolving)
   bei System.Data.DataTable.ReadXmlSerializable(XmlReader reader)
   bei System.Data.DataTable.System.Xml.Serialization.IXmlSerializable.ReadXml(XmlReader reader)
   bei System.Runtime.Serialization.XmlObjectSerializerReadContext.ReadIXmlSerializable(XmlSerializableReader xmlSerializableReader, XmlReaderDelegator xmlReader, XmlDataContract xmlDataContract, Boolean isMemberType)
   bei System.Runtime.Serialization.XmlDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)
   bei System.Runtime.Serialization.XmlObjectSerializerReadContext.ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader)
   bei System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, Type declaredType, DataContract&amp; dataContract)
   bei System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, DataContract dataContract, String name, String ns)
...

有几个条目具有不同的持续时间...有时异常发生在1秒之后,有时在9之后,但它始终是相同的异常。

2 个答案:

答案 0 :(得分:0)

如果它有时有效,有时候你不必在服务器和客户端站点检查wcf日志以确定出错的地方。在这种情况下,我怀疑客户端。您已经有服务器端的跟踪日志记录,尝试将其添加到客户端站点并检查客户端和服务器日志中的错误:

启用跟踪(确保dir c:\ log退出并且您具有正确的访问权限):

<configuration>
<system.diagnostics>
  <sources>
        <source name="System.ServiceModel" 
                switchValue="Information, ActivityTracing"
                propagateActivity="true">
        <listeners>
           <add name="traceListener" 
               type="System.Diagnostics.XmlWriterTraceListener" 
               initializeData= "c:\log\Traces.svclog" />
        </listeners>
     </source>
  </sources>
</system.diagnostics>
</configuration>

Tracing WCF

答案 1 :(得分:0)

咨询了WebServices的专家后,他给了我关键字 MTOM (Message Transmission Optimization Mechanism)。通常,WebServices不是为传输大数据集而设计的,但是通过MTOM增强,这是可能的。

我的新web.config:

<behaviors>
  <serviceBehaviors>
    <behavior name="svcBehavior">
      <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
      <serviceDebug includeExceptionDetailInFaults="true"/>
      <dataContractSerializer maxItemsInObjectGraph="2147483646"/>
    </behavior>
  </serviceBehaviors>
</behaviors>

<bindings>
  <wsHttpBinding>
    <binding name="MTOMBinding"
             messageEncoding="Mtom"
             closeTimeout="00:10:00"
             openTimeout="00:10:00"
             sendTimeout="00:10:00"
             maxBufferPoolSize="2147483647"
             maxReceivedMessageSize="2147483647">
      <readerQuotas maxDepth="2147483647"
                    maxStringContentLength="2147483647"
                    maxArrayLength="2147483647"
                    maxBytesPerRead="2147483647"
                    maxNameTableCharCount="2147483647" />
    </binding>
  </wsHttpBinding>
</bindings>

<services>
  <service behaviorConfiguration="svcBehavior" name="DBUpdateService.UpdateService">
    <endpoint address="" binding="wsHttpBinding" bindingConfiguration="MTOMBinding" contract="DBUpdateService.IDBUpdater" />
  </service>
</services>

app.config(客户端)

<system.serviceModel>
  <bindings>
    <wsHttpBinding>
      <binding name="MTOMBinding" closeTimeout="00:01:00" openTimeout="00:01:00"
          receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false"
          transactionFlow="false" hostNameComparisonMode="StrongWildcard"
          maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647"
          messageEncoding="Mtom" textEncoding="utf-8" useDefaultWebProxy="true"
          allowCookies="false">
        <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="2147483647"
            maxBytesPerRead="4096" maxNameTableCharCount="16384" />
      </binding>
    </wsHttpBinding>
  </bindings>
    <client>
        <endpoint address="http://xxx/UpdateService.svc"
                  binding="wsHttpBinding" 
                  bindingConfiguration="MTOMBinding"
                  contract="UpdateService.IDBUpdater" />
    </client>
</system.serviceModel>

我正在使用wsHttpBinding,但我确信MTOM也可以与其他绑定一起使用。我完全删除了所有其他绑定,因为在web.config中也配置了basicHttpBinding时,客户端和服务器无法交换数据。但我确信如果配置正确完成则没有必要。

我使用数据表运行了一些测试,这些数据包包含超过20万行,这些行由Web服务多次传输,并且没有CommunicationException!因此,如果您的Web服务和大型数据集出现问题,请尝试MTOM!