Downloading of zip file through ASP.NET MVC using DotNetZip

just a fix to Klaus solution: (as I can not add comment I have to add another answer!)

The solution is great but for me it gave corrupted zip file and I realized that it is because of return is before finalizing zip object so it did not close zip and result in a corrupted zip.

so to fix we need to just move return line after using zip block so it works. the final result is :

/// <summary>
///     Zip a file stream
/// </summary>
/// <param name="originalFileStream"> MemoryStream with original file </param>
/// <param name="fileName"> Name of the file in the ZIP container </param>
/// <returns> Return byte array of zipped file </returns>
private byte[] GetZippedFiles(MemoryStream originalFileStream, string fileName)
{
    using (MemoryStream zipStream = new MemoryStream())
    {
        using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
        {
            var zipEntry = zip.CreateEntry(fileName);
            using (var writer = new StreamWriter(zipEntry.Open()))
            {
                originalFileStream.WriteTo(writer.BaseStream);
            }
        }
        return zipStream.ToArray();
    }
}

/// <summary>
///     Download zipped file
/// </summary>
[HttpGet]
public FileContentResult Download()
{
    var zippedFile = GetZippedFiles(/* your stream of original file */, "hello");
    return File(zippedFile, // We could use just Stream, but the compiler gets a warning: "ObjectDisposedException: Cannot access a closed Stream" then.
                "application/zip",
                "sample.zip");
}

First of all, consider a way without creating any files on the server's disk. Bad practise. I'd recommend creating a file and zipping it in memory instead. Hope, you'll find my example below useful.

/// <summary>
///     Zip a file stream
/// </summary>
/// <param name="originalFileStream"> MemoryStream with original file </param>
/// <param name="fileName"> Name of the file in the ZIP container </param>
/// <returns> Return byte array of zipped file </returns>
private byte[] GetZippedFiles(MemoryStream originalFileStream, string fileName)
{
    using (MemoryStream zipStream = new MemoryStream())
    {
        using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
        {
            var zipEntry = zip.CreateEntry(fileName);
            using (var writer = new StreamWriter(zipEntry.Open()))
            {
                originalFileStream.WriteTo(writer.BaseStream);
            }
            return zipStream.ToArray();
        }
    }
}

/// <summary>
///     Download zipped file
/// </summary>
[HttpGet]
public FileContentResult Download()
{
    var zippedFile = GetZippedFiles(/* your stream of original file */, "hello");
    return File(zippedFile, // We could use just Stream, but the compiler gets a warning: "ObjectDisposedException: Cannot access a closed Stream" then.
                "application/zip",
                "sample.zip");
}

Notes to the code above:

  1. Passing a MemoryStream instance requires checks that it's open, valid and etc. I omitted them. I'd rather passed a byte array of the file content instead of a MemoryStream instance to make the code more robust, but it'd be too much for this example.
  2. It doesn't show how to create a required context (your file) in memory. I'd refer to MemoryStream class for instructions.

You may use the controller's File method to return a file, like:

public ActionResult Download()
{
    using (ZipFile zip = new ZipFile())
    {
        zip.AddDirectory(Server.MapPath("~/Directories/hello"));
        zip.Save(Server.MapPath("~/Directories/hello/sample.zip"));
        return File(Server.MapPath("~/Directories/hello/sample.zip"), 
                                   "application/zip", "sample.zip");
    }
}

If the zip file is not required otherwise to be stored, it is unnecessary to write it into a file on the server:

public ActionResult Download()
{
    using (ZipFile zip = new ZipFile())
    {
        zip.AddDirectory(Server.MapPath("~/Directories/hello"));

        MemoryStream output = new MemoryStream();
        zip.Save(output);
        return File(output.ToArray(), "application/zip", "sample.zip");
    }  
}