Learn ASP.NET MVC, ASP.NET Core, and Design Patterns through our online training programs. Courses conducted by Bipin Joshi on weekends. Read more details here.

Select, Zip and Download Files Programmatically in ASP.NET MVC

You might have already seen 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 you will learn how to do just that.

Consider the following sample application:

As you can see, 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 adding of the selected files to it happens programmatically in an ASP.NET MVC controller.

To develop this example, begin by creating a new ASP.NET MVC application (empty project template). Then add two folders namely Images and ZippedFiles under the project root folder. The Images folder contains the source files and the ZippedFiles folder contains the zip file. Also add a few image files to the Images folder. We use image files purely for the sake of simplicity. You can use any file types instead of image files.

Then add HomeController to the Controllers folder and modify its Index() action as shown below:

public ActionResult Index()
{
    string[] files = Directory.GetFiles(
                    Server.MapPath("~/images"));
    List<string> downloads = new List<string>();
    foreach(string file in files)
    {
        downloads.Add(Path.GetFileName(file));
    }
    return View(downloads);
}

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 and is shown below:

[HttpPost]
public ActionResult ProcessForm(List<string> selectedfiles)
{
    if(System.IO.File.Exists(Server.MapPath
                      ("~/zipfiles/bundle.zip")))
    {
        System.IO.File.Delete(Server.MapPath
                      ("~/zipfiles/bundle.zip"));
    }
    ZipArchive zip = ZipFile.Open(Server.MapPath
             ("~/zipfiles/bundle.zip"), ZipArchiveMode.Create);
    foreach (string file in selectedfiles)
    {
        zip.CreateEntryFromFile(Server.MapPath
             ("~/images/" + file), file);
    }
    zip.Dispose();
    return File(Server.MapPath("~/zipfiles/bundle.zip"), 
              "application/zip","bundle.zip");
}

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 this list for us.

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

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 foreach 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 - full path of the file to sent to the client browser, the MIME content type of the file and the file name t be displayed in the browser's download dialog.

Now, add Index view and place the following markup in it.

@model List<string>
...
<h1>List of files</h1>
<table border="1" cellpadding="10">
@using (Html.BeginForm("ProcessForm", 
             "Home", FormMethod.Post))
{
  foreach (string file in Model)
  {
    <tr>
      <td><input type="checkbox" 
           name="selectedfiles" value="@file" /></td>
      <td>@file</td>
    </tr>
  }
  <tr>
    <td colspan="2">
      <input type="submit" value="Download Selected Files" />
    </td>
  </tr>
}
</table>
</body>
</html>

The Index  view simply iterates through the List of files sent from the 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.

That's it! Run the application, select a few files and click the download button. The browser should prompt you to save Bundle.zip file.




Bipin Joshi is a software consultant, trainer, author and a yogi having 21+ years of experience in software development. He conducts online courses in ASP.NET MVC / Core, jQuery, AngularJS, and Design Patterns. He is a published author and has authored or co-authored books for Apress and Wrox press. Having embraced Yoga way of life he also teaches Ajapa Meditation to interested individuals. To know more about him click here.

Get connected : Twitter  Facebook  Google+  LinkedIn

Posted On : 21 Sep 2015



Tags : ASP.NET MVC C#