2016-05-03 5 views
0

Ich habe ASP.NET Web API-Projekt, wo ein Benutzer einige Sachen aus einer Datenbank herunterladen kann. Mein Download-Controller ruft Daten von der Datenbankinstanz ab. Jedes einzelne Ergebnis hat ein Blob-Feld, das irgendeine Art von Daten ist (1). Ich möchte jedes Ergebnis in eine ZIP-Datei (2) hinzufügen. Immerhin sende ich die HTTP-Antwort, indem ich meinen Stream-Inhalt hinzufüge.Erstellen von zipFile Auspuff Speicher

List<Result> results = m_Repository.GetResultsForResultId(given_id_by_request); 

// 1 
foreach (Result result in results) 
{ 
    string fileName = String.Format("{0}-{1}.bin", id >> 16, result.Id); 
    zipFile.AddEntry(fileName, result.Value); 
} 

// 2 
PushStreamContent pushStreamContent = new PushStreamContent((stream, content, context) => 
{ 
    zipFile.Save(stream); 
    stream.Close(); 
} 

response = new HttpResponseMessage(HttpStatusCode.OK) { Content = pushStreamContent }; 

Es funktioniert gut! Aber bei großen Download-Anfragen erschöpft dies mein Gedächtnis. Ich muss einen Weg finden, einen Strom in ein zip-Archiv ohne Puffer zu setzen. Kann mir bitte jemand helfen ?!

+0

Sieht so aus, als gäbe es eine andere Frage [Zip-Datei aus dem Stream erstellen und herunterladen] (http://stackoverflow.com/a/2267750/2127492), die diese Art von Problem abdeckt. Die beste Antwort sollte Ihnen bei Ihrem Problem helfen. – jrbeverly

Antwort

1

Soweit ich aus dem von Ihnen geposteten Code sehen kann, entsorgen Sie die Streams, die Sie nach der Verwendung erstellen, nicht. Dies kann zu einer großen Menge an Speicher beitragen, der von Ihrer App reserviert wird, was zu Problemen führen kann.

Ich verwende die ZipArchive, um mehrere Dateien in eine Zip-Datei in meiner Webanwendung zu legen. Der Code sieht etwas wie folgen aus:

using (var compressedFileStream = new MemoryStream()) 
     { 
      using (var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Update, false)) 
      { 
       foreach (Result result in results) 
       { 
        string fileName = String.Format("{0}-{1}.bin", id >> 16, result.Id); 
        var zipEntry = zipArchive.CreateEntry(fileName); 

        using (var originalFileStream = new MemoryStream(result.Value)) 
        { 
         using (var zipEntryStream = zipEntry.Open()) 
         { 
          originalFileStream.CopyTo(zipEntryStream); 
         } 
        } 
       } 
      } 

      return File(compressedFileStream.ToArray(), "application/zip", string.Format("Download_{0:ddMMyyy_hhmm}.zip", DateTime.Now)); 
} 

ich den Code-Snippet innerhalb einer MVC-Controller-Methode verwenden, so dass Sie den Rückteil für Ihre Situation anpassen.

Der obige Code funktioniert gut in meiner Anwendung für bis zu 300 Einträge oder 50MB Volumen (das sind die durch die Anforderungen für meine App festgelegten Grenzen).

Hoffnung, die Ihnen hilft.

BEARBEITEN: Die schließende Klammer des ersten verwendenden Blocks wurde vergessen. Die return-Anweisung muss innerhalb dieses using-Blocks liegen, sonst wird der Stream entsorgt.

+0

Vielen Dank für das Snippet. Ich werde es versuchen! Der Rückgabewert muss eine HttpResponse mit HttpContent als Inhaltstyp sein. Vielleicht werde ich es mit laufen lassen: Antwort = neue HttpResponseMessage (HttpStatusCode.OK) {Inhalt = neuer StreamContent (compressedFileStream)}; – marrrschine

+0

Das sollte funktionieren. Vielleicht ist es eine gute Idee, den ContentType der Antwort auch auf "application/octet-stream" zu setzen – MarcoLaser

+0

Ich habe response = new hinzugefügt HttpResponseMessage (HttpStatusCode.OK) {Content = neuer StreamContent (compressedFileStream)}; response.Content.Headers.ContentType = neuer MediaTypeHeaderValue ("application/octet-stream"); response.Content.Headers.Add ("x-filename", string.Format ("{0} .zip", request.Dateiname)); Antwort zurücksenden; leider ohne Erfolg. – marrrschine

Verwandte Themen