2011-11-22 2 views
20

Ho creato un servizio Web in WCF che restituisce più di 54000 righe di dati con 10 dati in ogni riga. Ho usato il wsHttpBinding per la comunicazione. Il servizio funziona bene con meno dati (cioè 2000 righe) ma esplode quando si tenta di inviare un set di record di grandi dimensioni con oltre 50000 righe (~ 2 MB). Il messaggio di eccezione è uguale aTrasferimento di grandi quantità di dati nel servizio WCF

Si è verificato un errore durante la ricezione della risposta HTTP a http://localhost:9002/MyService.svc. Ciò potrebbe essere dovuto al binding dell'endpoint del servizio che non utilizza il protocollo HTTP. Ciò potrebbe anche essere dovuto a un contesto di richiesta HTTP interrotto dal server (probabilmente a causa dell'arresto del servizio). Vedi i log del server per maggiori dettagli.

Si prega di non dirmi di utilizzare l'impaginazione sul lato client - so che risolverà il problema. Ma ho bisogno dell'intera fetta di dati nel client-end.

mia configurazione del servizio sul server è come

<system.serviceModel> 
    <bindings> 
    <wsHttpBinding> 
     <binding name="MyWsHttpBinding" /> 
    </wsHttpBinding> 
    </bindings> 
    <services> 
    <service name="AdminService"> 
     <endpoint address="AdminSrv" 
       binding="wsHttpBinding" 
       contract="IAdminService"/> 
     <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> 
     <host> 
     <baseAddresses> 
      <add baseAddress="/Bus/IRfotoWCF" /> 
     </baseAddresses> 
     </host> 
    </service> 
    </services> 
    <behaviors> 
    <serviceBehaviors> 
     <behavior> 
     <!-- To avoid disclosing metadata information, 
        set the value below to false and remove the metadata endpoint above before deployment --> 
     <serviceMetadata httpGetEnabled="True"/> 
     <!-- To receive exception details in faults for debugging purposes, 
        set the value below to true. Set to false before deployment 
        to avoid disclosing exception information --> 
     <serviceDebug includeExceptionDetailInFaults="True" /> 
     </behavior> 
    </serviceBehaviors> 
    </behaviors> 
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true"></serviceHostingEnvironment> 
</system.serviceModel> 

La mia configurazione client è come

<system.serviceModel> 
    <bindings> 
    <basicHttpBinding> 
     <binding name="BasicHttpBinding_IAdminService" closeTimeout="00:01:00" 
       openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" 
       allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" 
       maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" 
       messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" 
       useDefaultWebProxy="true"> 
     <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" 
         maxBytesPerRead="4096" maxNameTableCharCount="16384" /> 
     <security mode="None"> 
      <transport clientCredentialType="None" proxyCredentialType="None" realm="" /> 
      <message clientCredentialType="UserName" algorithmSuite="Default" /> 
     </security> 
     </binding> 
    </basicHttpBinding> 
    </bindings> 
    <client> 
    <endpoint address="http://localhost/TestService/AdminService.svc" 
       binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IAdminService" 
       contract="IAdminService" name="BasicHttpBinding_IAdminService" /> 
    </client> 
</system.serviceModel> 

Qualcuno mi può aiutare con la configurazione di esata sia sul lato client e server. Anche se ho bisogno di cambiare il binding da wsHttpBinding a netTcpBinding - non ho alcun problema a farlo. Grazie in anticipo.

risposta

33

Dopo molte indagini ho finalmente trovato la soluzione. In realtà è necessario modificare una serie di cose.

Le seguenti modifiche devono essere eseguite su lato server.

Prima ho dovuto impostare un maxRequestLength ad un valore più grande nel mio elemento httpRuntime per eseguire la richiesta di periodo più lungo.

<system.web>  
<httpRuntime maxRequestLength="102400" /> 
</system.web> 

Seconda ho introdotto netTcpBinding binnding con modifiche personalizzate su maxBufferSize, maxBufferPoolSize, maxReceivedMessageSize con un grande valore 2147483647.

<binding name="myNetTcpBinding" 
maxBufferPoolSize="2147483647" 
maxBufferSize="524288" 
maxReceivedMessageSize="2147483647"> 

Terzo aggiungere maxItemsInObjectGraph sia del serviceBehaviors e endpointBehaviors come soffietto (non dimenticate di citare i nomi di comportamento nel nodo service e endpoint)

<behaviors> 
     <serviceBehaviors>   
     <behavior name="myNetTcpBehaviour"> 
      <serviceMetadata httpGetEnabled="true"/> 
      <serviceDebug includeExceptionDetailInFaults="true"/> 
      <dataContractSerializer maxItemsInObjectGraph="2147483647"/> 
     </behavior> 
     </serviceBehaviors> 
     <endpointBehaviors> 
     <behavior name="myNetTcpEndPointBehaviour"> 
      <dataContractSerializer maxItemsInObjectGraph="2147483647"/> 
     </behavior> 
     </endpointBehaviors> 
    </behaviors> 

Infine mio aspetto di configurazione del server così

<system.web>  
    <httpRuntime maxRequestLength="102400" /> 
</system.web> 


    <system.serviceModel> 
    <bindings> 
     <wsHttpBinding> 
     <binding name="MyWsHttpBinding" /> 
     </wsHttpBinding> 
     <netTcpBinding> 
     <binding name="myNetTcpBinding" 
       closeTimeout="00:01:00" 
       openTimeout="00:01:00" 
       receiveTimeout="00:10:00" 
       sendTimeout="00:01:00" 
       transactionFlow="false" 
       transferMode="Buffered" 
       transactionProtocol="OleTransactions" 
       hostNameComparisonMode="StrongWildcard" 
       listenBacklog="10" 
       maxBufferPoolSize="2147483647" 
       maxBufferSize="524288" 
       maxConnections="10" 
       maxReceivedMessageSize="2147483647"> 
      <readerQuotas maxDepth="32" 
         maxStringContentLength="8192" 
         maxArrayLength="16384" 
         maxBytesPerRead="4096" 
         maxNameTableCharCount="16384" /> 
      <reliableSession ordered="true" 
          inactivityTimeout="00:10:00" 
          enabled="false" /> 
      <security mode="Transport"> 
      <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" /> 
      </security> 
     </binding> 
     </netTcpBinding> 
    </bindings> 
    <services> 
     <service name="AdminService" behaviorConfiguration="myNetTcpBehaviour"> 
     <endpoint address="AdminSrv" 
        binding="netTcpBinding" 
        bindingConfiguration="myNetTcpBinding" 
        contract="IAdminService" 
        behaviorConfiguration="myNetTcpEndPointBehaviour"/> 

     <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> 
     <host> 
      <baseAddresses> 
      <add baseAddress="/Bus/IRfotoWCF" /> 
      </baseAddresses> 
     </host> 
     </service> 
    <behaviors> 
     <serviceBehaviors>   
     <behavior name="myNetTcpBehaviour"> 
      <serviceMetadata httpGetEnabled="true"/> 
      <serviceDebug includeExceptionDetailInFaults="true"/> 
      <dataContractSerializer maxItemsInObjectGraph="2147483647"/> 
     </behavior> 
     </serviceBehaviors> 
     <endpointBehaviors> 
     <behavior name="myNetTcpEndPointBehaviour"> 
      <dataContractSerializer maxItemsInObjectGraph="2147483647"/> 
     </behavior> 
     </endpointBehaviors> 
    </behaviors> 
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true"></serviceHostingEnvironment> 
    </system.serviceModel> 

Ora sul lato client configuratioin è necessario cambiare il maxBufferSize="2147483647" maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647"

e anche è necessario aggiungere maxItemsInObjectGraph="2147483647" in configurazione comportamento degli endpoint.

 <endpointBehaviors> 
      <behavior name="myEndPointBehavior"> 
       <dataContractSerializer maxItemsInObjectGraph="2147483647" /> 
      </behavior> 
     </endpointBehaviors> 

ora posso trasmettere delle righe in 5,30 min in cui la query eseguita per 10 secondi in modo che il tempo di trasmissione è 5,20 min - ancora molto.

Sentitevi liberi di commentare e qualsiasi suggerimento per il miglioramento.

+0

Non capisco. È davvero una buona soluzione, quando un servizio attende un altro servizio durante 5,20 minuti. Penso che qui sia la grande domanda sull'architettura, ma non riesco a trovare una soluzione. – Vladislav

+0

Continuo a testare la velocità con il trasferimento di big data. Usando il metodo "Chunks" posso inviare 300.000 (!) Righe, salvarlo nel database entro 4.34 min senza alcuna modifica nelle configurazioni del mio servizio. Sono solo separati i miei dati per blocchi con 50 righe. – Vladislav

+0

È necessario utilizzare il serializzatore Datacontract anziché XML. Questo è finora un lavoro di sostituzione manuale all'interno di reference.cs. – NickD

1

Se si osservano i dettagli di binding essi non corrispondono interamente al server e a quello del lato client. Anche gli attributi per maxBufferSize, maxBufferPoolSize, maxReceivedMessageSize devono essere definiti sul lato server. E poi devi mettere i valori in base alla dimensione che stai guardando.

+0

Ho provato questi maxBufferSize, maxBufferPoolSize, maxReceivedMessageSize con i valori 2147483647 sia sul lato server che sul lato client. Ancora la stessa eccezione. –

+0

Non sono riuscito a vedere le impostazioni nel file di configurazione nel tuo post. Sei sicuro che la configurazione vincolante sia impostata correttamente? – Kangkan

+0

Yap, ho configurato quelli nella configurazione di binding in locale sia sul lato server che lato client. Ma ora ho risolto il problema: vedi la risposta. Grazie comunque, sentitevi liberi di commentare la risposta. –

-3

Invece di utilizzare per loop su WCF per dati voluminosi, utilizzare il tipo di tabella definito dall'utente (se si utilizza SQL). Ridurrà il tempo da 6 minuti a 15-20 secondi.

+0

Proprio cosa ......? – Gareth