Working With Zip Files In ASP.NET MVC

5 (5 votes)

Since ASP.NET 4.5, zipping and unzipping files can be done with classes from within the .NET framework. Despite that, nearly all examples that illustrate working with zip files in ASP.NET applications feature third party open source compression libraries. This short article attempts to correct that by demonstrating the use of the System.IO.Compression classes to unpack an uploaded zip file, and to create one for download in an ASP.NET MVC application.

Unpacking an uploaded zip file

To begin, you need to add a reference to System.IO.Compression to your project. Having done that, here is an upload form for the zip file:

@using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    <input type="file" name="zip"  /> 
    <div>
        <button class="btn btn-default">Submit</button>
    </div>
}

Note that the form's method is specified as POST and that the enctype attribute is set with a value of multipart/form-data - both prerequisites for being able to upload files. The form is posted to the following controller action:

[HttpPost]
public ActionResult Index(HttpPostedFileBase zip)
{
    var uploads = Server.MapPath("~/uploads");
    using (ZipArchive archive = new ZipArchive(zip.InputStream))
    {
        foreach (ZipArchiveEntry entry in archive.Entries)
        {
            if (!string.IsNullOrEmpty(Path.GetExtension(entry.FullName))) //make sure it's not a folder
            {
                entry.ExtractToFile(Path.Combine(uploads, entry.FullName));
            }
            else
            {
                Directory.CreateDirectory(Path.Combine(uploads, entry.FullName));
            }
        }
    }
    ViewBag.Files = Directory.EnumerateFiles(uploads);
    return View();
}

The action's parameter is an HttpPostedFileBase named after the name attribute of the file upload control in the form. The code creates an instance of the ZipArchive class from the content of the uploaded file and then iterates the contents of the archive. If the name of an entry has a file extension, it is a file. If not, it is a folder. The code will save the extracted file or create a folder accordingly.

Creating a Zip file for download

The simple example that follows illustrates the use of the static ZipFile.CreateFromDirectory method which, despite the fact that it is in the System.IO.Compression namespace , actually resides in the System.IO.Compression.FileSystem assembly, so you need to add a reference to that in your controller. The user is presented with a list of checkboxes representing a selection of files to choose from. Submitting the form will result in just those files being packaged up into one zip file and downloaded.

The list of files is passed to the view via ViewBag:

public ActionResult Index()
{
    ViewBag.Files = Directory.EnumerateFiles(Server.MapPath("~/pdfs"));
    return View();
}

The files are listed within a form with a set of checkboxes:

<h2>Select downloads</h2>
@using(Html.BeginForm("Download", "Home"))
{
    foreach(string file in ViewBag.Files)
    {
        <input type="checkbox" name="files" value="@file" /> @:&nbsp;  
             @Path.GetFileNameWithoutExtension(file) <br />
    }
    <div>
        <button class="btn btn-default">Submit</button>
    </div>
}

The form posts to an action called Download which consists of the following code:

[HttpPost]
public FileResult Download(List<string> files)
{
    var archive = Server.MapPath("~/archive.zip");
    var temp = Server.MapPath("~/temp");

    // clear any existing archive
    if (System.IO.File.Exists(archive))
    {
        System.IO.File.Delete(archive);
    }
    // empty the temp folder
    Directory.EnumerateFiles(temp).ToList().ForEach(f => System.IO.File.Delete(f));

    // copy the selected files to the temp folder
    files.ForEach(f => System.IO.File.Copy(f, Path.Combine(temp, Path.GetFileName(f))));

    // create a new archive
    ZipFile.CreateFromDirectory(temp, archive);

    return File(archive, "application/zip", "archive.zip");
}

The user selection is captured in the files parameter. The code checks to see if a file called archive.zip exists from previous operations and it it does, it is deleted. Then a folder called temp is cleared of any existing files. Next,the selected files are copied from their source directory to the temp folder. The ZipFile.CreateFromDirectory method generates a zip file from the temp directory contents and saves it as archive.zip. Finally, it is written to the Response.

Both of these examples are simplified to illustrate the main classes and methods required to perform the tasks as clearly as possible. When handling the upload, you should add validation to check that the uploaded file is in fact a zip file, for example. Also, the zip file that gets created is placed into a hardcoded folder. If you have a busy site where multiple users are downloading zip files at the same time, you may want to use a Guid as a folder name instead to avoid the possibility of one user's download overwriting another.

Date Posted:
Last Updated:
Posted by:
Total Views to date: 7512

2 Comments

- Suraj

Very nice article. Thanks.

- Daniele

is it possible give to the user a progress bar of the zipping process?
Thanks in advance.

Recent Comments

Thomas 05/03/2018 00:59
In response to I'm Not Writing A Book On Razor Pages
There's a typo on this page: = true)] should be [BindProperty(SupportsGet = true)]...

Rolf Herbert 04/03/2018 19:25
In response to I'm Not Writing A Book On Razor Pages
So is MS deprecating razor Web Pages..? Is it dead..? I wish they would stop killing things so its...

Borut 17/02/2018 12:59
In response to I'm Not Writing A Book On Razor Pages
Mike, is it possible that Web Pages and Razor Pages "live" together in one web application? I a I...

hrboyce 09/02/2018 04:44
In response to I'm Not Writing A Book On Razor Pages
Mike, First thanks for doing this but I have to ask, any chance you would consider converting one of...

aziz sallam 07/02/2018 10:18
In response to I'm Not Writing A Book On Razor Pages
u are a great man...

Satyabrata Mohapatra 31/01/2018 11:36
In response to I'm Not Writing A Book On Razor Pages
This is a great news!!!! Thanks...

tangdf 30/01/2018 07:25
In response to I'm Not Writing A Book On Razor Pages
=> { o.ConfigureFilter(new IgnoreAntiforgeryTokenAttribute()); }); The extension method does...

Obinna Okafor 30/01/2018 04:02
In response to I'm Not Writing A Book On Razor Pages
Thank you very much. I would like to see a project built from scratch using Razor Pages. And it show...

rachida Dukes 31/10/2017 13:52
In response to Customising Identity in Razor Pages
Thanks again for this wonderful tutorial. I followed all the steps in this section called: Adding...

Rachida 31/10/2017 12:06
In response to Customising Identity in Razor Pages
Thanks very much for this wonderful tutorial, it helped a lot....