1

I try to download multiple files from a web API in .NET Core 3.1 and put them in a zip archive written in the response body. When I download the zip file with the browser the zip file is corrupted!

Controller :

public async Task DownloadFilesAsync([FromServices] IFileService fileService, [FromBody] IEnumerable<Guid> fileIds, Guid folderId)
{
    HttpContext.Response.Headers.Add("Content-Disposition", $"{DispositionTypeNames.Attachment};filename*=files.zip");
    HttpContext.Response.ContentType = MediaTypeNames.Application.Zip;
    await fileService.GetZipAsync(User.UserId(), folderId, fileIds, HttpContext.Response.Body);
}

Service :

public async Task GetZipAsync(Guid userId, Guid folderId, IEnumerable<Guid> fileIds, Stream stream)
{
    using (ZipArchive zip = new ZipArchive(stream, ZipArchiveMode.Create, leaveOpen: true))
    {
        foreach (Guid id in fileIds)
        {
            // metadata stored in a sql database, File is a custom type
            File file = await _fileRepository.GetFileAsync(folderId, id);
            using Stream entry = zip.CreateEntry(file.Name, CompressionLevel.Optimal).Open();
            await _fileStorage.WriteBlobAsync(userId, folderId, file.Name, entry);
        }
    }
}

Storage repository :

public async Task WriteBlobAsync(Guid userId, Guid folderId, string name, Stream output)
{
    BlobContainerClient container = Client.GetBlobContainerClient(userId.ToString());
    await container.GetBlobClient($"{folderId}/{name}").DownloadToAsync(output);
}

But the downloaded zip archive is unusable:

Zip archive content

What have I done wrong?

Andreas
  • 5,393
  • 9
  • 44
  • 53
Shadam
  • 1,041
  • 13
  • 25
  • For those who pass by here, the code above is perfectly functional. see the accepted answer below... – Shadam Aug 31 '22 at 10:41

2 Answers2

0

Ok, I'm feeling myself a little stupid on this one...

This code is perfectly good on the back side, my problem was on the client side.

It was missing a { responseType: 'arraybuffer' } on my axios request configuration...

Shadam
  • 1,041
  • 13
  • 25
-1

Method 1.

You can try to dispose ZipArchive And error should be solved.

public async Task GetZipAsync(Guid userId, Guid folderId, IEnumerable<Guid> fileIds, Stream stream)
{
    using (ZipArchive zip = new ZipArchive(stream, ZipArchiveMode.Create, leaveOpen: true))
    {
        foreach (Guid id in fileIds)
        {
            // metadata stored in a sql database, File is a custom type
            File file = await _fileRepository.GetFileAsync(folderId, id);
            using Stream entry = zip.CreateEntry(file.Name, CompressionLevel.Optimal).Open();
            await _fileStorage.WriteBlobAsync(userId, folderId, file.Name, entry);
        }
        //I added this line 
        zip.Dispose();
    }
}

Method 2.

You can set the stream's AutoFlush property to true.

For more details, you can refer below link.

ZipArchive gives Unexpected end of data corrupted error

Jason Pan
  • 15,263
  • 1
  • 14
  • 29
  • 2
    Huh? `using` automatically calls `Dispose`. How would disposing of `zip` twice help? – Zer0 May 25 '21 at 04:12
  • @Zer0 Sorry, I add wrong place. I have updated, try it. – Jason Pan May 25 '21 at 04:12
  • That's still a double dispose. That line doesn't need to exist. That's what the `using` keyword does. – Zer0 May 25 '21 at 04:14
  • @Zer0 https://stackoverflow.com/questions/47707862/ziparchive-gives-unexpected-end-of-data-corrupted-error/47707973 – Jason Pan May 25 '21 at 04:17
  • Pick a solution from another thread is not a good practice, I already searched across sof and don't found any working solution. The linked post has already been tested without any success. And as say @Zer0 `Dispose()` twice the ZipArchive has no reason to be done – Shadam May 26 '21 at 16:05