Download Files In Zip Format Using ASP.NET MVC Razor And SweetAlert Library

Introduction

There are so many websites that display a list of files to the end user. The user can then select one or more files from the list and request a zipped bundle of those files as a single download. In this article I will show you this implementation using MVC.


Description

The page displays a list of files residing on the server. Each file has a checkbox that indicates whether that file is to be included in the download bundle or not. After selecting one or more checkboxes, you can click the "Download Selected Files" button to zip all the selected files and then download them. The creation of the zip file and addition of the selected files can be done programmatically in an ASP.NET MVC Controller.

Project Link

Go to my own GitHub link to download this Project.
Steps to be followed.

Step 1

Add the DLL files are in reference folder of the project.



Step 2


Create a Controller named "HomeController.cs".

Code Ref
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Web;  
  5. using System.Web.Mvc;  
  6. using System.IO;  
  7. using System.IO.Compression;  
  8.   
  9. namespace SatyaMultipleZipDownload.Controllers  
  10. {  
  11.     public class HomeController : Controller  
  12.     {  
  13.         public ActionResult Index()  
  14.         {  
  15.             string[] files = Directory.GetFiles(  
  16.                             Server.MapPath("~/images"));  
  17.             List<string> downloads = new List<string>();  
  18.             foreach (string file in files)  
  19.             {  
  20.                 downloads.Add(Path.GetFileName(file));  
  21.             }  
  22.             return View(downloads);  
  23.         }  
  24.   
  25.         [HttpPost]  
  26.         public ActionResult ProcessForm(List<string> selectedfiles)  
  27.         {  
  28.             if (System.IO.File.Exists(Server.MapPath  
  29.                               ("~/zipfiles/bundle.zip")))  
  30.             {  
  31.                 System.IO.File.Delete(Server.MapPath  
  32.                               ("~/zipfiles/bundle.zip"));  
  33.             }  
  34.             ZipArchive zip = ZipFile.Open(Server.MapPath  
  35.                      ("~/zipfiles/bundle.zip"), ZipArchiveMode.Create);  
  36.             foreach (string file in selectedfiles)  
  37.             {  
  38.                 zip.CreateEntryFromFile(Server.MapPath  
  39.                      ("~/images/" + file), file);  
  40.             }  
  41.             zip.Dispose();  
  42.             return File(Server.MapPath("~/zipfiles/bundle.zip"),  
  43.                       "application/zip""Satya.zip");  
  44.         }  
  45.     }  

Code Description

Add the most important namespaces as below.
  1. using System.IO;  
  2. using System.IO.Compression; 

The code uses GetFiles() method of Directory class (System.IO namespace) to retrieve a list of files in the Images folder.  It then adds those files to a List.

Notice that GetFiles() returns the full path and file name for all the files. While adding these files to the generic List, we pick only the file name. This is done using the GetFileName() method of Path class. The List is then passed to the Index View as its model.
 
Next, add another action - ProcessForm() - to the HomeController. The ProcessForm() action does the job of creating the zip file. The classes such as ZipArchieve and ZipFile come from System.IO.Compression namespace and hence you need to add a reference to System.IO.Compression.dll and System.IO.Compression.FileSystem.dll assemblies.

The ProcessForm() action receives a List of strings. This list is nothing but a list of values of the checkboxes displayed on the page. The ASP.NET MVC model binding framework is intelligent enough to fill in this list for us.

The code checks whether a file named Bundle.zip already exists on the Server. If so, the file is deleted. Bundle.zip is the file that gets dynamically created in the next steps. If you wish, you can generate this name dynamically also.

Then, Open() method of ZipFile class is used to create Bundle.zip file inside the ZipFiles folder. The return value of Open() method is ZipArchive object. Then, a For Each loop iterates through the selectedfiles List. For every selected file its full path is formed using the MapPath() method and is fed to the CreateEntryFromFile() method of the ZipArchive object.

Once all the files are added to Bundle.zip, the file is returned using the File() method. The File() method takes three parameters, the full path of the file to sent to the client browser, the MIME content type of the file, and the file name to be displayed in the browser's download dialog.

Then, we add two folders namely Images and ZipFiles under the project root folder. The Images folder contains the source files and the ZipFiles folder contains the zip files. Also, add a few image files to the Images folder. We're using image files purely for the sake of simplicity. You can use any file types instead of image files like pdf , word , excel etc.

The zip file is downloaded with name "Satya.zip" inside ProcessForm action result method. But the file name will be found with name bundle.zip inside zipfiles folder. 
  1. return File(Server.MapPath("~/zipfiles/bundle.zip"),  
  2.                       "application/zip""Satya.zip");  
Step 3

Create a View named "Index.cshtml".

Code Ref
  1. @model List<string>  
  2. <title>Satyaprakash File Download In Zip</title>  
  3. <link href="~/App_Content/CSS/bootstrap.min.css" rel="stylesheet" />  
  4. <link href="~/App_Content/CSS/font-awesome.min.css" rel="stylesheet" />  
  5. <style>  
  6.     table {  
  7.         font-family: arial, sans-serif;  
  8.         border-collapse: collapse;  
  9.         width: 100%;  
  10.     }  
  11.   
  12.     td, th {  
  13.         border: 1px solid #dddddd;  
  14.         text-align: left;  
  15.         padding: 8px;  
  16.     }  
  17.   
  18.     tr:nth-child(even) {  
  19.         background-color: #dddddd;  
  20.     }  
  21.   
  22.     .button {  
  23.         background-color: #4CAF50;  
  24.         border: none;  
  25.         color: white;  
  26.         padding: 15px 32px;  
  27.         text-align: center;  
  28.         text-decoration: none;  
  29.         display: inline-block;  
  30.         font-size: 16px;  
  31.         margin: 4px 2px;  
  32.         cursor: pointer;  
  33.     }  
  34.   
  35.     .button4 {  
  36.         border-radius: 9px;  
  37.     }  
  38. </style>  
  39.   
  40. <h1>Collection Of Files</h1>  
  41.   
  42. <link href="~/Scripts/sweetalert.css" rel="stylesheet" />  
  43. <script src="~/Scripts/jquery-1.10.2.js"></script>  
  44. <script src="~/Scripts/sweetalert.js"></script>  
  45.   
  46.   
  47. <div align="center">  
  48.     <table align="center" border="1" cellpadding="4" cellspacing="4">  
  49.         <thead>  
  50.             <tr>  
  51.                 <th style="background-color: Yellow;color: blue">Select</th>  
  52.                 <th style="background-color: Yellow;color: blue">File Name</th>  
  53.             </tr>  
  54.         </thead>  
  55.         @using (Html.BeginForm("ProcessForm""Home", FormMethod.Post, new { @enctype = "multipart/form-data" }))  
  56.         {  
  57.             foreach (string file in Model)  
  58.             {  
  59.                 <tr>  
  60.                     <td>  
  61.                         <input type="checkbox" id="fileUpload"  
  62.                                name="selectedfiles" value="@file" />  
  63.                     </td>  
  64.                     <td style="color: blue">@file</td>  
  65.                 </tr>  
  66.             }  
  67.             <tr>  
  68.                 <td colspan="2">  
  69.                     <input type="submit" id="fileUploadExcel" onclick="return validateData();" class="button button4" value="Download" />  
  70.                 </td>  
  71.             </tr>  
  72.         }  
  73.     </table>  
  74. </div>  
  75.   
  76. <script>  
  77.     //code for validation using checkbox  
  78.     function validateData() {        
  79.         if ($('[type="checkbox"]').is(':checked')) {  
  80.             sweetAlert("Congratulations!!""Your file is downloaded""success");  
  81.             return true;  
  82.         }  
  83.             //else if ($('[type="checkbox"]').not(':checked')) {  
  84.             //    sweetAlert("Selection Was Empty!!", "Please select at least one", "error");  
  85.             //    return false;  
  86.             //}  
  87.         else {  
  88.             sweetAlert("Selection Was Empty!!""Please select at least one""error");  
  89.             return false;  
  90.         }  
  91.     }  
  92. </script> 
Code Description

The Index View simply iterates through the list of files sent from Controller and displays a table. The BeginForm() helper posts the form to the ProcessForm() action.
 
Notice how the checkboxes are displayed. All the checkboxes have the same name - selectedfiles - and this name must match with the parameter of ProcessForm() action. The value attribute of the checkboxes is set to the name of the file.
 
I have added a table inside div tag, put checkbox, and uploaded file name display and button.
  1. <table align="center" border="1" cellpadding="4" cellspacing="4">  
  2.         <thead>  
  3.             <tr>  
  4.                 <th style="background-color: Yellow;color: blue">Select</th>  
  5.                 <th style="background-color: Yellow;color: blue">File Name</th>  
  6.             </tr>  
  7.         </thead>  
  8.         @using (Html.BeginForm("ProcessForm""Home", FormMethod.Post, new { @enctype = "multipart/form-data" }))  
  9.         {  
  10.             foreach (string file in Model)  
  11.             {  
  12.                 <tr>  
  13.                     <td>  
  14.                         <input type="checkbox" id="fileUpload"  
  15.                                name="selectedfiles" value="@file" />  
  16.                     </td>  
  17.                     <td style="color: blue">@file</td>  
  18.                 </tr>  
  19.             }  
  20.             <tr>  
  21.                 <td colspan="2">  
  22.                     <input type="submit" id="fileUploadExcel" onclick="return validateData();" class="button button4" value="Download" />  
  23.                 </td>  
  24.             </tr>  
  25.         }  
  26.     </table> 
I created a script file to validate if the checkbox is selected or not, and the Sweet Alert popup will be shown to the end user.
  1. <script>  
  2.     //code for validation using checkbox  
  3.     function validateData() {        
  4.         if ($('[type="checkbox"]').is(':checked')) {  
  5.             sweetAlert("Congratulations!!""Your file is downloaded""success");  
  6.             return true;  
  7.         }  
  8.             //else if ($('[type="checkbox"]').not(':checked')) {  
  9.             //    sweetAlert("Selection Was Empty!!", "Please select at least one", "error");  
  10.             //    return false;  
  11.             //}  
  12.         else {  
  13.             sweetAlert("Selection Was Empty!!""Please select at least one""error");  
  14.             return false;  
  15.         }  
  16.     }  
  17. </script> 
Then, I added the function "validateData()" inside button's onclick event.
  1. <input type="submit" id="fileUploadExcel" onclick="return validateData();" class="button button4" value="Download" />  
OUTPUT

Desktop View

WIth no file selection for download.



With any file selection for download.



Then, download the zip file path.



Mobile View




Summary
 
We learned:
  1. How to download the uploaded files in zip format.
  2. How to validate if the checkboxes are checked or not, using MVC.
  3. The message to be shown to the end user using Sweet Alert library.