2012-04-11 18 views
6

Abbiamo un servizio Web (asmx) che accetta un buffer di array di byte e lo invia a un servizio di file esterno per l'archiviazione e l'archiviazione. Viene chiamato da un servizio di Windows che genera file di dimensioni ridotte (3-5 M), quindi la creazione di un array di byte di tale dimensione e l'alimentazione come parametro per la chiamata al servizio web ha funzionato bene fino ad ora.Streaming di file di grandi dimensioni sul servizio Web

Sono stato incaricato di aggiungere un nuovo lavoro alla coda file che potenzialmente genererà file di> 70 M. Ovviamente una dimensione byte[] sommergerà la memoria di sistema, quindi ho cercato soluzioni. Il servizio web ha un metodo interno che prende uno FileStream come parametro invece di uno byte[], quindi ho provato ad emettere il metodo FileStream come un metodo Web. Ho aggiornato i riferimenti nel servizio di Windows, ma accade una cosa strana: il parametro FileStream ha uno specificatore di namespace allegato (qualcosa come CallingWindowsService.ExternalWebServiceFileManager.FileStream) e questo oggetto specificato non accetta alcun nome di file come costruttore, quindi non posso aprire uno specifico file.

Sono totalmente in mare su come avvicinarsi a questo. Qualcun altro ha fatto questo - lo streaming di grandi quantità di dati da a un servizio web - e se sì, qual è il metodo migliore? Il mio servizio web avrà bisogno di uno byte[] o FileStream.

Guardando attraverso alcuni degli altri messaggi, sembra che MTOM (che non ha familiarità con esso) potrebbe essere una soluzione, ma non sono sicuro di come configurarlo nei miei metodi web o farlo funzionare.

risposta

1

ASMX i servizi Web sono una tecnologia legacy che non dovrebbe essere utilizzata per nuovi sviluppi.

Una delle funzionalità che manca è il supporto per lo streaming e file di grandi dimensioni. In particolare, un messaggio verrà duplicato in memoria fino a quattro volte in uscita verso il cliente.

WCF supporta lo streaming reale.

+0

La buona notizia è che abbiamo deciso di aggiungere la funzionalità a un servizio WCF esistente, in modo che la parte ricevente sia gestita. Sono ancora in mare, però, a proposito di chiamare il servizio dal mio servizio di Windows. La funzione che chiama il servizio di trasmissione file prende un byte [] come parametro, quindi la mia routine di creazione file deve restituire quel buffer. Sembra che ho bisogno di refactoring in modo che il buffer è dichiarato nella routine di creazione di file e quella routine chiama il servizio iterativamente per trasmettere il file in blocchi? –

+0

Forse refactoring tutto per utilizzare flussi invece di matrici di byte? MemoryStream può essere costruito da un array di byte. –

-1

Come ha detto @John Saunders, i servizi Web hanno scarso supporto per lo streaming e l'elaborazione di dimensioni di file di grandi dimensioni, è possibile utilizzare la compressione per trasmettere il file tramite il servizio Web anziché inviare il file non elaborato.

+0

-1: "servizi web" non ha problemi di streaming dei file. Solo i precedenti servizi web ASMX hanno questo problema. –

3

È possibile provare alcune cose, non si menzionano i protocolli che si utilizzano o il modo in cui lo si ospita, quindi presumo che possa essere IIS7 e il proprio utilizzo di sapone. Nel file web.config del servizio web è possibile aggiungere la seguente che aumenterà la dimensione del file consentita per il trasferimento senza l'errore 404:

<system.web> 
    <httpRuntime executionTimeout="999999" maxRequestLength="2097151" /> 
    ... 
    </system.web> 

La seconda cosa che si potrebbe desiderare di fare per Web del servizio web. file di configurazione per consentire il trasferimento di file di grandi dimensioni:

<system.webServer> 
    <security> 
     <requestFiltering> 
     <requestLimits maxAllowedContentLength="2000000000" /> 
     </requestFiltering> 
    </security> 
    </system.webServer> 

Altra possibilità:

<location path="Copy.asmx"> <!-- Name of you asmx --> 
    <system.webServer> 
     <security> 
     <requestFiltering> 
      <requestLimits maxAllowedContentLength="104857600"/> <!-- 100 megs --> 
     </requestFiltering> 
     </security> 
    </system.webServer> 
    </location> 

Il problema principale con l'invio di byte [] 's su servizi web è che essi g et inserire nel corpo SOAP che viene codificato come una stringa 64 di base. I file di codifica come questo aumentano le dimensioni del file fino a due terzi nel corpo del sapone (ad esempio un file da 6 MB diventa un file da 9 MB sul filo).

Un'altra possibilità è "chunking" che divide i dati in segmenti più piccoli prima della trasmissione, che può essere tutto ciò che serve. Il chunkSize (impostato su 500 KB) può essere un fattore chiave per migliorare le prestazioni del caricamento in base a fattori quali velocità della rete, risorse del server, ecc.

/// <summary> 
/// Chunk the file and upload 
/// </summary> 
/// <param name="filename"></param> 
private void UploadVideo(string filename) 
{ 
    #region Vars 
    const int chunkSize = 512000; 
    byte[] bytes = null; 
    int startIndex, endIndex, length, totalChunks;   

    WS.UploadRequest objRequest = new WS.UploadRequest();    
    #endregion 

    try 
    { 
     if (File.Exists(filename)) 
     { 
      using (WS.UploadService objService = new WS.UploadService()) 
      { 
       using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) 
       { 
        //// Calculate total chunks to be sent to service 
        totalChunks = (int)Math.Ceiling((double)fs.Length/chunkSize); 

        //// Set up Upload request object 
        objRequest.FileName = filename; 
        objRequest.FileSize = fs.Length; 

        for (int i = 0; i < totalChunks; i++) 
        { 
         startIndex = i * chunkSize; 
         endIndex = (int)(startIndex + chunkSize > fs.Length ? fs.Length : startIndex + chunkSize); 
         length = endIndex - startIndex; 
         bytes = new byte[length]; 

         //// Read bytes from file, and send upload request 
         fs.Read(bytes, 0, bytes.Length); 
         objRequest.FileBytes = bytes; 
         objService.UploadVideo(objRequest); 
        } 
       } 

      } 
     } 
    } 
    catch (Exception ex) 
    { 
     MessageBox.Show(string.Format("Error- {0}", ex.Message)); 
    } 
Problemi correlati