2012-10-16 7 views
5

Próbuję utworzyć plik zip w metodzie MVC przy użyciu komponentów DotNetZip.Używanie memorystream i DotNetZip w MVC daje "Nie można uzyskać dostępu do zamkniętego strumienia"

Oto mój kod:

public FileResult DownloadImagefilesAsZip() 
    { 
     using (var memoryStream = new MemoryStream()) 
     { 
      using (var zip = new ZipFile()) 
      { 
       zip.AddDirectory(Server.MapPath("/Images/")); 
       zip.Save(memoryStream); 

       return File(memoryStream, "gzip", "images.zip"); 
      } 
     } 
    } 

Kiedy go uruchomić dostaję „nie można uzyskać dostępu do zamkniętego Stream” błąd i nie jestem pewien dlaczego.

Odpowiedz

15

Nie wyrzucać MemoryStream The FileStreamResult zajmie po jego zakończeniu pisania go do odpowiedzi:

public ActionResult DownloadImagefilesAsZip() 
{ 
    var memoryStream = new MemoryStream(); 
    using (var zip = new ZipFile()) 
    { 
     zip.AddDirectory(Server.MapPath("~/Images")); 
     zip.Save(memoryStream); 
     return File(memoryStream, "application/gzip", "images.zip"); 
    } 
} 

Przy okazji polecam piszesz wynik niestandardowych działań obsłużyć to zamiast pisanie kodu instalacyjnego wewnątrz akcji kontrolera. Nie tylko, że otrzymasz wynik działania wielokrotnego użytku, ale pamiętaj, że twój kod jest niezwykle nieefektywny => wykonujesz operację ZIP w pamięci i tym samym ładujesz całą zawartość katalogu ~/images + plik zip w pamięci. Jeśli masz dużo użytkowników i dużo plików w tym katalogu, bardzo szybko zabraknie Ci pamięci.

O wiele bardziej efektywnym rozwiązaniem jest napisać bezpośrednio do strumienia odpowiedzi:

public class ZipResult : ActionResult 
{ 
    public string Path { get; private set; } 
    public string Filename { get; private set; } 

    public ZipResult(string path, string filename) 
    { 
     Path = path; 
     Filename = filename; 
    } 

    public override void ExecuteResult(ControllerContext context) 
    { 
     if (context == null) 
     { 
      throw new ArgumentNullException("context"); 
     } 

     var response = context.HttpContext.Response; 
     response.ContentType = "application/gzip"; 
     using (var zip = new ZipFile()) 
     { 
      zip.AddDirectory(Path); 
      zip.Save(response.OutputStream); 
      var cd = new ContentDisposition 
      { 
       FileName = Filename, 
       Inline = false 
      }; 
      response.Headers.Add("Content-Disposition", cd.ToString()); 
     } 
    } 
} 

, a następnie:

public ActionResult DownloadImagefilesAsZip() 
{ 
    return new ZipResult(Server.MapPath("~/Images"), "images.zip"); 
} 
+0

Perfect! Bardzo dziękuję :) –

+1

Musiałem dodać 'memoryStream.Seek (0, SeekOrigin.Begin);' before 'return File (...);', aby to działało. – pqvst

0

Nie można skomentować.

Odpowiedź Darina jest świetna! Nadal otrzymałem wyjątek pamięci, więc musiałem dodać response.BufferOutput = false; i dlatego musiałem przesunąć kod dyspozycji treści wyżej.

Więc trzeba:

... 
     var response = context.HttpContext.Response; 
     response.ContentType = "application/zip"; 
     response.BufferOutput = false; 

     var cd = new ContentDisposition 
     { 
      FileName = ZipFilename, 
      Inline = false 
     }; 
     response.Headers.Add("Content-Disposition", cd.ToString()); 

     using (var zip = new ZipFile()) 
     { 
... 

wszelki wypadek nie było oczywiste :)

Powiązane problemy