web-dev-qa-db-fra.com

Transférer une grande quantité de données dans le service WCF

J'ai créé un service Web dans WCF qui renvoie plus de 54 000 lignes de données avec 10 données dans chaque ligne. J'ai utilisé le wsHttpBinding pour la communication. Le service fonctionne bien avec moins de données (c'est-à-dire 2000 lignes) mais il se bombe lorsque vous tentez d'envoyer un grand jeu d'enregistrements avec plus de 50000 lignes (~ 2 Mo). Le message d'exception est comme ceci

Une erreur s'est produite lors de la réception de la réponse HTTP à http://localhost:9002/MyService.svc. Cela peut être dû au fait que la liaison de point de terminaison de service n'utilise pas le protocole HTTP. Cela peut également être dû à un contexte de requête HTTP interrompu par le serveur (peut-être en raison de l'arrêt du service). Voir les journaux du serveur pour plus de détails.

S'il vous plaît, ne me dites pas d'utiliser la pagination du côté client - je sais que cela résoudra le problème. Mais j'ai besoin de la totalité du bloc de données côté client.

Ma configuration de service sur le serveur est la

<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>

Ma configuration client est la

<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>

Quelqu'un pourrait-il m'aider avec la configuration exacte à la fois côté client et côté serveur? Même si j'ai besoin de changer la liaison de wsHttpBinding à netTcpBinding - je n'ai aucun problème à le faire. Merci d'avance.

20
Rizvi Hasan

Après beaucoup d'investigations, j'ai finalement trouvé la solution. En fait, un certain nombre de choses doivent être modifiées.

Les modifications suivantes devaient être effectuées dans côté serveur.

First J'ai dû définir un maxRequestLength sur une valeur plus grande dans mon httpRuntime élément pour exécuter la demande pendant une période plus longue.

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

Second j'ai introduit netTcpBinding binnding avec des modifications personnalisées sur maxBufferSize, maxBufferPoolSize, maxReceivedMessageSize avec une grande valeur de 2147483647.

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

Troisième ajoutez maxItemsInObjectGraph dans les deux serviceBehaviors et endpointBehaviors comme ci-dessous (n'oubliez pas de mentionner les noms de comportement dans le service et endpoint node)

    <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>

Enfin ma configuration de serveur ressemble à ceci

<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>

Maintenant, sur la configuration côté client, vous devez changer le maxBufferSize="2147483647" maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647"

et vous devez également ajouter maxItemsInObjectGraph="2147483647" dans la configuration du comportement du point de terminaison.

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

Maintenant, je peux transmettre lignes dans 5,30 min où la requête a été exécutée pendant 10 secondes, donc le temps de transmission est de 5,20 min - toujours beaucoup.

N'hésitez pas à commenter et à suggérer des améliorations.

33
Rizvi Hasan

Si vous regardez les détails de liaison, ils ne correspondent pas entièrement du côté serveur et du côté client. Les attributs pour maxBufferSize, maxBufferPoolSize, maxReceivedMessageSize doivent également être définis côté serveur. Et puis vous devez mettre les valeurs en fonction de la taille que vous regardez.

1
Kangkan