Creating and downloading zip files with ASP.NET Core

For a recent feature, I had to download a batch of files from an internal website written in ASP.NET Core. Zipping the files before downloading them, turned out as a great way of easily implementing multi-file download. .NET offers all of the needed features and in this post, I'll show you how to implement it.

Creating and downloading zip files with ASP.NET Core

To get started, I'll create a new ASP.NET Core website:

dotnet new mvc

I'm picking the MVC template, but none of the zip-related code is specific to MVC.

For this example, I'll create a single endpoint able to zip and download some files. In real-life, input parameters would often be required for the backend to know what to zip, but I'll leave that part out for simplicity.

Start by declaring the method without a body:

[Route("downloadzip")]
public async Task<IActionResult> DownloadTheZipFile()
{
    // ...
}

The code doesn't compile yet, so let's fix that. Start by building a list of files to zip. In the following code, I'll hard-code some paths, but each file could come from the client, from a database, or something third:

List<string> files = new List<string>
{
    "first/file.txt",
    "second/file.txt"
};

Next, we need the zipping code:

using (var memoryStream = new MemoryStream())
{
    using (var zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
    {
        foreach (var file in files)
        {
            zipArchive.CreateEntryFromFile(file, Path.GetFileName(file));
        }
    }
}

The code uses the ZipArchive class available in .NET, to create the zip file. It's wrapped in a MemoryStream since we want to return a file stream from the method:

memoryStream.Position = 0;
return File(memoryStream, "application/zip", "download.zip");

After resetting the stream, I'm returning it as part of the File-method. To get an overview of the various possibilities of returning files from ASP.NET Core, check out the following post: How to download files from ASP.NET Core MVC.

Here's the entire method:

[Route("downloadzip")]
public async Task<IActionResult> DownloadTheZipFile()
{
    List<string> files = new List<string>
    {
        "first/file.txt",
        "second/file.txt"
    };

    using (var memoryStream = new MemoryStream())
    {
        using (var zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
        {
            foreach (var file in files)
            {
                zipArchive.CreateEntryFromFile(file, Path.GetFileName(file));
            }
        }
        
        memoryStream.Position = 0;
        return File(memoryStream, "application/zip", "my.zip");
    }
}

Hit F5 and call the /downloadzip endpoint to see magic happen.

The example in this post is pretty simple and doesn't take any problems into account. If you are dealing with large zip files, it may be more efficient to write the zip file to a temporary file on the server and then stream the file to the client. This can help prevent memory issues that might arise from trying to hold the entire zip file in memory at once:

var tempFile = Path.GetTempFileName();

using (var zipFile = System.IO.File.Create(tempFile))
using (var zipArchive = new ZipArchive(zipFile, ZipArchiveMode.Create))
{
    foreach (var file in files)
    {
        zipArchive.CreateEntryFromFile(file, Path.GetFileName(file));
    }
}

var stream = new FileStream(tempFile, FileMode.Open);
return File(stream, "application/zip", "my.zip");

Also, remember that zipping and downloading large files may take some time. Implementing some kind of progress on the client can avoid the user from trying to download the zip file multiple times, taking up additional server resources.

That's it. Zipping files in .NET is easy using the built-in classes. To be fair, there are some good external NuGet packages available as well. Like SharpZipLib (I have used this in the past) and DotNetZip. Make sure to check out all three options to see which approach you like best.

elmah.io: Error logging and Uptime Monitoring for your web apps

This blog post is brought to you by elmah.io. elmah.io is error logging, uptime monitoring, deployment tracking, and service heartbeats for your .NET and JavaScript applications. Stop relying on your users to notify you when something is wrong or dig through hundreds of megabytes of log files spread across servers. With elmah.io, we store all of your log messages, notify you through popular channels like email, Slack, and Microsoft Teams, and help you fix errors fast.

See how we can help you monitor your website for crashes Monitor your website