Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Convert File into Zip and download With Ajax and MVC

4.09/5 (6 votes)
23 Feb 2017CPOL4 min read 42K   1.3K  
This article is about how to convert files into Zip and download as single Zip.

Introduction

Now a days almost every websites supports download file feature. Now as a developer we face several issue when providing such funtionality. Let see the problems:

  1. We must know the file content type on client side to save it in proper format.
  2. As browsers cann't handle every type of file as some of them do not have any MimeType defined like '.bak' files.
  3. Sometimes, browser at client machine does not allows you to download file as it might be harmful in nature.

So we have to find a way to overcome such problems and the solution is zipping the file .i.e. 'ZIP'. Zipping files also has its own benefits apart from solving the mentioned problems like it also compress the file size thus making web bandwidth consumption low and thus increasing website as a user experience. So let's start it.

Background

The background is the knowledge of MVC. You should know how to add a project in MVC and add a Controller. If you wants to start with MVC first you can learn it from my other articles as listed below: As we will be using ajax so knowledge of Jquery is also pre-requisite. We will be creating a page which will be having a button that will post a ajax request to server and server will return file as a zip.

Start-With-MVC-Push-Start-For-Beginners-Part - 1

Start-With-MVC-Push-Start-For-Beginners-Part - 2

Start-With-MVC-Push-Start-For-Beginners-Part - 3

Using the Code

We will be using DotNetZip library for zipping files. Please visit this link DotNetZip

We also be using javascript FileSaver.js library for saving the zip files. Please visit this link FileSaver.js

Now add an MVC project. I assume that you have created a HomeController and Index method in it. The index method will return a index cshtml View. Now We will add a mthod which will be invoked on click of a button from Index page.

So basically our process will be like:

Load Index Page >> 'Click Download Zip' >> Invoke Ajax post method >> Invoke MVC Controller Method (Which will be using DotNetZip library and Zip the files) >> save file.

Let first add the DotNetZip library reference to our project. For that you need to navigate to Tools >> NuGet package Manager >> Package Manager Console

Now type the following command: 'Install-Package DotNetZip' (without quotes). Now you have installed the DotNetZip library and you can verify it from 'References' folder in SolutionExplorer window.

Now add the FileServer.js library reference to our project/HTML. For this you can either download FileSaver.js file from server and its refence into html or use cdn path as I used.

Now follow the steps to create a working demo.

Step 1: Add using reference to 'HomeController' using using Ionic.Zip;

SolutionFolderImage

So you can see its quite simple Index method is added. Now let see the code in our CSHTML page (Index.cshtml).

Step 2: Add Images to Image folder.

Here is the image of my Project folder structure. I have added an Image folder to project and added two images into it so that I can zip these images and download.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Ionic.Zip;
using System.IO;

namespace Zip_In_MVC.Controllers
{
    public class HomeController : Controller
    {
        //
        // GET: /Home/
        
        public ActionResult Index()
        {
            return View();
        }
        
    }
}

So you can see its quite simple structure. Now lets start writing the code for a method/action that will return the files as a single zip file.

C#
public FileResult DownloadFiles()
{
    //Define file Type
    string fileType = "application/octet-stream";
            
    //Define Output Memory Stream
    var outputStream = new MemoryStream();

    //Create object of ZipFile library
    using (ZipFile zipFile = new ZipFile())
    {
        //Add Root Directory Name "Files" or Any string name
        zipFile.AddDirectoryByName("Files");

        //Get all filepath from folder
        String[] files = Directory.GetFiles(Server.MapPath("/Images"));
        foreach (string file in files)
        {
            string filePath = file;

            //Adding files from filepath into Zip
            zipFile.AddFile(filePath, "Files");
        }
               
        Response.ClearContent();
        Response.ClearHeaders();

        //Set zip file name
        Response.AppendHeader("content-disposition", "attachment; filename=PuneetGoelDotNetZip.zip");

        //Save the zip content in output stream
        zipFile.Save(outputStream);
    }

    //Set the cursor to start position
    outputStream.Position = 0;

    //Dispance the stream
    return new FileStreamResult(outputStream, fileType);
}

So you can see its quite simple code and its self explanatory. Enter your doubts in comment if any

Step 3: Index.cshtml View Code

Below is the html code that has A simple download button that will call the above method and in result downloads a zip file that will have two files zipped in it.

HTML
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width" />
        <title>Zipping File In MVC</title>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.3/FileSaver.min.js"></script>
    </head>
    <body>
        <p>Click on the link below to download zip file</p>
        <a id="ancDownloadFiles" href="@Html.AttributeEncode(Url.Action("DownloadFiles", "Home"))">Download</a>
    </body>
</html>

Till now we have a running code that will download files as a single Zip Unit with compressed size. You can download the code file in link attached with this article. Further we will see how we can use an ajax call for the same.

Step 4: Updating code to download File with Ajax Call.

Now this is the main step which is problematic in most cases. It is verfy tricky to download a file content 'blob' as a file and save it as a zip. For this I have added a script reference (filesaver.js) as you can see in above html code as well. Below is the full code.

HTML
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Zipping File In MVC</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.3/FileSaver.min.js"></script>
    <script type="text/javascript">
        function downloadFiles() {
            debugger
            var ajax = new XMLHttpRequest();
            ajax.open("Post", "Home/DownloadFiles", true);
            ajax.responseType = "blob";
            ajax.onreadystatechange = function () {
                if (this.readyState == 4) {
                    debugger;
                    var blob = new Blob([this.response], { type: "application/octet-stream" });
                    var fileName = "PuneetGoelDotNetZip.zip";
                    saveAs(blob, fileName);

                }
            };
            ajax.send(null);
        }
    </script>
</head>
<body>
    <p>Zip and Download</p>
    <a id="cancelUrl" href="@Html.AttributeEncode(Url.Action("DownloadFiles", "Home"))">Download</a>
    <br />
    <a id="cancelUrl" href="#" onclick="downloadFiles();">Download With Ajax</a>
</body>
</html>

Note: I have used plain HttpRequest as : jQuery ajax is not able to handle binary responses properly (can't set responseType), so it's better to use a plain XMLHttpRequest call.  For more detail on this, you can read this Stackoverflow link.

Now you have full code, you just need to build the project and run it. Whola!! You have done it.

Points of Interest

You can convert as many as file you want into a single zip and push to client machine. You bandwidth is saved. You can also save a MemoryStream object to zip and download that. Keep in mind jquery doesn't support 'blob' till the time and we can have some workaround but using plain XmlHttpRequest is always a winner.

Things to learn

You can learn how we can modify juery request to save blob/binary/arraybuffer objects.

You can learn how we can save zip blob directly without using third party api/script/plugins.

That's all from my side for this article, comments and suggestions are welcomed.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)