The question is how can I create a zipped (compressed) folder on the fly using ASP.NET Core 2 (currently) Web API?
I am using System.IO.Compression.ZipArchive
I have been several blog posts where this is done using streams or byte arrays, all give me the same output.
I am able to download the zip folder but unable to open it.
The zipped folder is the correct size. Even though it doesn't open.
They way I want it to work is for a user to click a button which runs this action and return a zipped folder containing one or multiple files.
[HttpGet]
[Route("/api/download/zip")]
public async Task<IActionResult> Zip()
{
byte[] bytes = null;
using (MemoryStream zipStream = new MemoryStream())
using (var zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
{
var tempFileName = await _azure.GetFilesByRef("Azure_FilePath");
// Running just this line gives me the zipped folder (empty) which I can open
ZipArchiveEntry entry = zip.CreateEntry("File1.pdf", CompressionLevel.Fastest);
// Adding this 2nd section will download the zip but will not open the zip folder
using (Stream stream = entry.Open())
using (FileStream fs = new FileStream(tempFileName, FileMode.Open, FileAccess.Read))
{
await fs.CopyToAsync(stream);
}
bytes = zipStream.ToArray();
}
return File(bytes, MediaTypeNames.Application.Zip, $"Attachments{DateTime.Now.ToBinary()}.zip");
}
Can anyone spot a mistake or suggest an alternative solution?
All the data is not written to the stream until the archive is disposed. So in this case, the data in the stream may be incomplete if the archive has not flushed it as yet.
memoryStream.ToArray
is being called before the archive has a chance to flush all its data to the underlying stream.Consider refactoring to
The assumption in your example is also that the
FileStream
opened is the correct file type of the created entry; A single PDF file. Otherwise consider extracting a name from thetempFileName
.You have to add a unique entry (file path) for each item you want added to the archive.