PROWAREtech

articles » current » asp-net-core » zipfile-stream

ASP.NET Core: ZipFile Stream Options in .NET 8 and Later

Covers the new streaming options in the .NET 8 ZipFile class; written in C#.

As of now, the ZipFile class can extract to a directory from a Stream class and write to a Stream from a directory. Before, when working with ZipFile, one had to "override" the Dispose() method in the FileStream class to delete the zip file after sending it to the browser (see article on this topic). Using the MemoryStream class instead of the FileStream class — while convenient — is inefficient and care must be taken when working with large amounts of data and/or large numbers of users.

Example Code

Create a .NET 8 Model-View-Controller (MVC) application project. Make the following additions and changes to the project.

Modify Index.cshtml

Modify the Index.cshtml file to be this:

@model IEnumerable<string>
@{
	ViewData["Title"] = "Home Page";
}

<div class="text-center">
	<h1 class="display-4">Welcome</h1>
	<p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

@* NOTE: NEWLY ADDED CODE *@
<div style="margin:10rem auto;width:400px;">
	<hr />
	<p><a href="/?downloadzip=true">download a zip file created with a stream</a></p>
	<hr />
	<form method="post" enctype="multipart/form-data">
		<table>
			<tr>
				<td><input type="file" accept="application/x-zip-compressed" name="zip-file" required /></td>
				<td><button type="submit">view zip file contents</button></td>
			</tr>
		</table>
	</form>
	<hr />
</div>
@if (Model != null)
{
	<h5>Contents</h5>
	<div>
		@foreach (var s in Model)
		{
			<div>@s</div>
		}
	</div>
}
@* NOTE: END OF NEWLY ADDED CODE *@

Modify HomeController.cs

Modify the HomeController.cs file to be this:

using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
using System.IO.Compression;  // NOTE: this line is newly added
using ZipFileExample.Models;

namespace ZipFileExample.Controllers
{
	public class HomeController : Controller
	{
		private readonly ILogger<HomeController> _logger;
		private readonly IWebHostEnvironment _env; // NOTE: this line is newly added

		public HomeController(ILogger<HomeController> logger, IWebHostEnvironment env)  // NOTE: this line is modified
		{
			_logger = logger;
			_env = env;  // NOTE: this line is newly added
		}



		// NOTE: following block of code/method is modified
		[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
		public IActionResult Index(bool downloadzip = false)
		{
			if (downloadzip)
			{
				using (var ms = new MemoryStream())
				{
					ZipFile.CreateFromDirectory(_env.WebRootPath, ms);
					return File(ms.ToArray(), "application/x-zip-compressed", "wwwroot.zip");
				}
			}
			return View();
		}


		// NOTE: following block of code/method is newly added
		[HttpPost]
		[DisableRequestSizeLimit] // NOTE: in production code, set a reasonable limit
		[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
		public IActionResult Index(IFormCollection form)
		{
			var model = new List<string>();
			if (Request.Form.Files.Count > 0 && Request.Form.Files[0].ContentType.ToLower() == "application/x-zip-compressed")
			{
				string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
				Directory.CreateDirectory(tempPath);
				using (var zipStream = Request.Form.Files[0].OpenReadStream())
				{
					ZipFile.ExtractToDirectory(zipStream, tempPath);
					foreach(var item in Directory.EnumerateFileSystemEntries(tempPath))
						model.Add(Path.GetFileName(item));
				}
				Directory.Delete(tempPath, true);
			}
			return View(model);
		}



		public IActionResult Privacy()
		{
			return View();
		}

		[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
		public IActionResult Error()
		{
			return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
		}
	}
}

Hit Ctrl+F5 to run the application and it should look like this:

ZipFile Stream Example

Now explore the new options on this page!


This site uses cookies. Cookies are simple text files stored on the user's computer. They are used for adding features and security to this site. Read the privacy policy.
CLOSE