2015-01-19 9 views
10

Sto cercando di caricare i file utilizzando un approccio simile HttpClient: How to upload multiple files at once in Windows Phone.Qual è la migliore strategia per caricare file di grandi dimensioni utilizzando HttpClient in un dispositivo Windows Phone con memoria insufficiente?

using (var content = new MultipartFormDataContent()) 
{ 
    content.Add(CreateFileContent(imageStream, "image.jpg", "image/jpeg")); 
    content.Add(CreateFileContent(signatureStream, "image.jpg.sig", "application/octet-stream")); 

    var response = await httpClient.PostAsync(_profileImageUploadUri, content); 
    response.EnsureSuccessStatusCode(); 
} 

private StreamContent CreateFileContent(Stream stream, string fileName, string contentType) 
{ 
    var fileContent = new StreamContent(stream); 
    fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") 
    { 
     Name = "\"files\"", 
     FileName = "\"" + fileName + "\"" 
    }; // the extra quotes are key here 
    fileContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);    
    return fileContent; 
} 

Questo funziona correttamente durante il caricamento di file di piccole dimensioni. Se ho provato a caricare file di dimensioni maggiori (ad esempio> 50mb) in un dispositivo di fascia bassa (memoria da 512 MB), lancia System.OutOfMemoryException. Ho usato gli strumenti diagnostici per monitorare il consumo di memoria e ho notato che la memoria cresce in modo esponenziale durante la chiamata PostAsync. Sembra che copi l'intero contenuto nella memoria. Al momento non abbiamo il supporto di chunking nell'api .

Qual è la strategia migliore per caricare file di grandi dimensioni utilizzando HttpClient in un dispositivo Windows Phone con memoria insufficiente?

+0

Ecco una soluzione: http://stackoverflow.com/questions/26223902/window-phone-8-submit-post-form-with-an-image/26243886#26243886 –

+1

Che dire 'di Windows. Networking.BackgroundTransfer.BackgroundUploader'? Guarda qui: http://stackoverflow.com/a/27430331/27211 – kiewic

+0

Tutte le chiamate API per il download e il caricamento sono implementate in un SDK (Portable class Library che supporta .net 4.5.1, Windows Phone 8.1 e Windows Store 8.1). Per quanto ne so il supporto per Windows.Networking.BackgroundTransfer.BackgroundUploader non è disponibile in PCL, correggere se ho torto. Devo implementarlo usando HttpClient. –

risposta

2

Non sono un vero esperto di MultipartFormDataContent (e potrebbe suddividere il contenuto sott'acqua) ma un consiglio potrebbe essere la divisione dei dati che si desidera inviare.

Quindi inviare gli altri blocchi e ricostruirlo sul lato ricevente.

ad es. dividere le immagini in blocchi più piccoli (ad esempio 10mb o meno in base all'utilizzo della memoria) e inviarli

In tal modo, un ciclo for può attraversare i blocchi.

foreach (byte[] block in dividedContent) 
{ 
    using (var content = new MultipartFormDataContent()) 
    { 
     content.Add(block); 

     var response = await httpClient.PostAsync(_profileImageUploadUri, content); 
     response.EnsureSuccessStatusCode(); 
    } 
} 

forse qualcosa di simile avrebbe risolto il problema :)

+0

Non ho alcun controllo su API lato server.Devo trovare un modo per caricare fino a quando l'api supporta il caricamento chunked. –

+0

divisoContenuto, e unirlo insieme come 7z multi archieve? Buona idea, ma non provarlo ancora – toha

5

inserisco multipart manualmente - senza l'aiuto di MultipartFormDataContent

Se è necessario inviare più parti, allora si potrebbe post-it altro manually, lettura dal file sorgente in blocchi buffer 4k.

Non è necessario farlo con i metodi asincroni. La soluzione è "controllo manuale su buffer 4k". Ma async sarebbe l'ideale, essendo la maggior parte thread/CPU efficiente.

Ecco un altro collegamento consigliato per capire come code multipart posts. E un altro per capire il protocollo, ecco un esempio di ciò che viene inviato sul flusso, illustrating the boundary markers

Inoltre, architettonicamente, io preferisco caricare i file separatamente su qualsiasi (modulo) dati. Questo evita completamente la pubblicazione multipart, rendendo le tue API atomiche e semplici. Potresti avere un servizio che archivia semplicemente un file caricato e restituisce l'URL o l'ID. Tale URL o ID può quindi essere referenziato con i tuoi dati e pubblicato successivamente.

+0

Non ho il controllo delle API del lato server. Sto cercando di seguire il secondo approccio. Prova anche con http://www.strathweb.com/2013/01/asynchronously-streaming-video-with-asp-net-web-api/. –

+1

Questo collegamento non è relativo a multipart e potrebbe confondere l'implementazione manuale se si inizia con la loro architettura asincrona. Dovresti iniziare con il mio link e imparare dal tuo link per applicare i metodi asynch. Esistono molti modi per implementare un flusso multiparte POST con buffer 4k manuale, ma la mia risposta generale è essenzialmente quella di farlo manualmente e di rinunciare a MultipartFormDataContent. – Todd