web-dev-qa-db-fra.com

Grand transfert de fichiers binaires (octet []) via WCF

J'essaie de créer un service WCF qui me permet d'envoyer de gros fichiers binaires des clients au service.

Cependant, je ne peux transférer avec succès que des fichiers jusqu'à 3-4 Mo. (J'échoue lorsque j'essaie de transférer 4,91 Mo et, bien sûr, quoi que ce soit au-delà)

L'erreur que j'obtiens si j'essaie d'envoyer le fichier 4,91 Mo est:

Message d'exception: Une erreur s'est produite lors de la réception de la réponse HTTP à http: // localhost: 56198/Service.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.

Message d'exception interne: La connexion sous-jacente a été fermée: une erreur inattendue s'est produite lors d'une réception.

Message d'exception interne: Impossible de lire les données de la connexion de transport: une connexion existante a été fermée de force par l'hôte distant.

Message d'exception interne: Une connexion existante a été fermée de force par l'hôte distant

Cette erreur se produit côté client dès que le fichier octet [] est envoyé en tant que paramètre de méthode à la méthode de service exposée.

J'ai un point d'arrêt sur la première ligne de la méthode de service, en cas de transferts de fichiers réussis (en dessous de 3 Mo), ce point d'arrêt est atteint et le fichier est transféré. Cependant dans ce cas, dès que la méthode est appelée, l'erreur survient. Le point d'arrêt du service n'est pas atteint en cas de cette erreur.

Je vais coller mes sections de mon service Web.config et de la page Asp (client) Web.config. Si vous avez également besoin du code qui envoie le fichier et accepte le fichier, faites-le-moi savoir, je l'enverrai également.

Service Web.Config

<system.serviceModel>
<bindings>
  <basicHttpBinding>
    <binding name="basicHttpEndpointBinding" closeTimeout="01:01:00"
      openTimeout="01:01:00" receiveTimeout="01:10:00" sendTimeout="01:01:00"
      allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
      maxBufferSize="2147483646" maxBufferPoolSize="2147483646" maxReceivedMessageSize="2147483646"
      messageEncoding="Mtom" textEncoding="utf-8" transferMode="StreamedRequest"
      useDefaultWebProxy="true">
      <readerQuotas maxDepth="2147483646" maxStringContentLength="2147483646" maxArrayLength="2147483646"
        maxBytesPerRead="2147483646" maxNameTableCharCount="2147483646" />
      <security mode="None">
        <transport clientCredentialType="None" proxyCredentialType="None"
          realm="" />
        <message clientCredentialType="UserName" algorithmSuite="Default" />
      </security>
    </binding>        
  </basicHttpBinding>      
</bindings>
    <services>
        <service behaviorConfiguration="DragDrop.Service.ServiceBehavior" name="DragDrop.Service.Service">
            <endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttpEndpointBinding" contract="DragDrop.Service.IService">
                <identity>
                    <dns value="localhost"/>
                </identity>
            </endpoint>
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        </service>
    </services>
    <behaviors>
        <serviceBehaviors>
            <behavior name="DragDrop.Service.ServiceBehavior">
                <serviceMetadata httpGetEnabled="true"/>
                <serviceDebug includeExceptionDetailInFaults="false"/>
      <dataContractSerializer maxItemsInObjectGraph="2147483646"/>
            </behavior>
        </serviceBehaviors>
    </behaviors>
</system.serviceModel>

Client (page Asp.net) Web.Config

<system.serviceModel>
<bindings>
   <basicHttpBinding>
      <binding name="BasicHttpBinding_IService" closeTimeout="00:01:00"
         openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
         allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
         maxBufferSize="2147483646" maxBufferPoolSize="2147483646" maxReceivedMessageSize="2147483646"
         messageEncoding="Mtom" textEncoding="utf-8" transferMode="StreamedResponse"
         useDefaultWebProxy="true">
         <readerQuotas maxDepth="2147483646" maxStringContentLength="2147483646" maxArrayLength="2147483646"
            maxBytesPerRead="2147483646" maxNameTableCharCount="2147483646" />
         <security mode="None">
            <transport clientCredentialType="None" proxyCredentialType="None"
               realm="">
               <extendedProtectionPolicy policyEnforcement="Never" />
            </transport>
            <message clientCredentialType="UserName" algorithmSuite="Default" />
         </security>
      </binding>
   </basicHttpBinding>
</bindings>

<behaviors>
  <endpointBehaviors>
    <behavior name="debuggingBehaviour">
      <dataContractSerializer maxItemsInObjectGraph="2147483646" />
    </behavior>
  </endpointBehaviors>
</behaviors>

<client>
   <endpoint address="http://localhost:56198/Service.svc" binding="basicHttpBinding"
      bindingConfiguration="BasicHttpBinding_IService" contract="ServiceReference.IService"
      name="BasicHttpBinding_IService" behaviorConfiguration="debuggingBehaviour" />
</client>
</system.serviceModel>
21
user402186

(Bien que je convienne que transfert en streaming serait préférable, ce qui suit devrait le faire fonctionner sans autres changements)

Vous devez également augmenter la longueur maximale des messages dans Web.config:

<configuration>
  <system.web>
  <httpRuntime maxMessageLength="409600"
    executionTimeoutInSeconds="300"/>
  </system.web>
</configuration>

Cela définira la longueur maximale du message à 400 Mo (le paramètre est en Ko). Vérifiez cette page MSDN pour plus d'informations.

17
Thorarin

Comme indiqué, essayez d'utiliser Streaming Transfer , voici un exemple de code montrant à la fois l'envoi et la réception (éventuellement) de grandes quantités de données à l'aide du transfert en streaming.

Utilisez une liaison comme celle-ci, notez les paramètres MaxReceivedMessageSize et TranferMode.

<binding name="Streaming_Binding" maxReceivedMessageSize="67108864"  
    messageEncoding="Text" textEncoding="utf-8" transferMode="Streamed">
</binding>

Ajoutez un code de service :

[OperationContract]
public Stream GetLargeFile()
{
    return new FileStream(path, FileMode.Open, FileAccess.Read);
}

[OperationContract]
public void SendLargeFile(Stream stream)
{
    // Handle stream here - e.g. save to disk    
    ProcessTheStream(stream);

    // Close the stream when done processing it
    stream.Close();
}

Et du code client :

public Stream GetLargeFile()
{
    var client = /* create proxy here */;
    try
    {
        var response = client.GetLargeFile();

        // All communication is now handled by the stream, 
        // thus we can close the proxy at this point
        client.Close();

        return response;
    }
    catch (Exception)
    {
        client.Abort();
        throw;
    }
}

public void SendLargeFile(string path)
{
    var client = /* create proxy here */;
    client.SendLargeFile(new FileStream(path, FileMode.Open, FileAccess.Read));
}

Assurez-vous également que vous n'obtenez pas de délai d'attente, un gros fichier peut prendre un certain temps à transférer (la réception par défaut TimeTout est de 10 minutes cependant).

Vous pouvez télécharger un exemple de code Microsoft WCF/WF ici (le lien C # supérieur est rompu au moment de l'écriture, mais d'autres exemples de code semblent corrects).

16
Jakob Möllås

Avez-vous envisagé d'utiliser Streaming Transfer?

Windows Communication Foundation (WCF) peut envoyer des messages à l'aide de transferts en mémoire tampon ou en flux. Dans le mode de transfert en mémoire tampon par défaut, un message doit être entièrement remis avant qu'un destinataire puisse le lire. En mode de transfert en continu, le récepteur peut commencer à traiter le message avant qu'il ne soit complètement remis. Le mode de diffusion en continu est utile lorsque les informations transmises sont longues et peuvent être traitées en série. Le mode de streaming est également utile lorsque le message est trop volumineux pour être entièrement mis en mémoire tampon.

http://msdn.Microsoft.com/en-us/library/ms789010.aspx

4
Nick

Je vais faire écho à ce que d'autres ont dit et dire que l'utilisation d'un transfert en continu est la voie à suivre lorsque vous utilisez Windows Communication Foundation. Voici un excellent guide qui explique toutes les étapes afin de diffuser des fichiers sur WCF. C'est assez complet et très instructif.

Le voici: Guide sur les fichiers en streaming sur WCF .

1
Derek W