Returning Multiple Files from MVC Action

Look at this SO solution: MVC Streaming Zip File

The advantage of this solution is that it streams the file to the client.

I just implemented this solution a couple of days ago and it worked fantastic.


Sorry for bumping an old question but...

Another alternative would be to initiate multiple file downloads using JavaScript, and serve files in two different Action Methods on ASP.NET's side.

You're saying you have a link:

On the view, i have an action link like "Click here to get those 2 files"

So make this link like this:

<a href="#" onclick="downloadFile(url1); downloadFile(url2);">Click to get 2 files</a>
<script src="download.js"></script>

I'm using download.js script found here but you can find plenty of different other options, see this SO question: starting file download with JavaScript for example


I would advice to create a zip file to include both the files using steps(ALGORITHM):

  1. Create a Zip file and add the desired files into the zip
  2. Return the zip file having all desired files from the action

Java Syntax (Just for understanding)

      FileOutputStream fos = new FileOutputStream("downloadFile.zip");
      ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(fos));
      zos.putNextEntry(new ZipEntry("Filename1.extension"+));
      //write data in FileName1.extension
      zos.write(contentBuffer1, 0, len);

      zos.putNextEntry(new ZipEntry("Filename2.extension"));
      //write data in FileName2.extension
      zos.write(contentBuffer2, 0, len);

      //write other files.....
      zos.close();

Once zip file is created, return the newly created zip file to download.

     return File("downloadFile.zip");

.DOT Net Equivalent using DotNetZip

     var os = new MemoryStream();

     using (var zip = new ZipFile())
     {
         //write the first file into the zip
         zip.AddEntry("file1.txt", "content1");

         //write the second file into the zip
         zip.AddEntry("file2.txt", "content2");

         //write other files.....
         zip.Save(os);
      }

      outputStream.Position = 0;
      return File(outputStream, "application/zip", "filename.zip");

Hope this helps!


Building on Yogendra Singh's idea and using DotNetZip:

var outputStream = new MemoryStream();

using (var zip = new ZipFile())
{
    zip.AddEntry("file1.txt", "content1");
    zip.AddEntry("file2.txt", "content2");
    zip.Save(outputStream);
}

outputStream.Position = 0;
return File(outputStream, "application/zip", "filename.zip");

Update 2019/04/10: As @Alex pointed out, zipping is supported natively since .NET Framework 4.5, from JitBit and others:

using (var memoryStream = new MemoryStream())
{
   using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
   {
      var file1 = archive.CreateEntry("file1.txt");
      using (var streamWriter = new StreamWriter(file1.Open()))
      {
         streamWriter.Write("content1");
      }

      var file2 = archive.CreateEntry("file2.txt");
      using (var streamWriter = new StreamWriter(file2.Open()))
      {
         streamWriter.Write("content2");
      }
   }

   return File(memoryStream.ToArray(), "application/zip", "Images.zip")
}