0

I'm using Angular 6 and ASP.Net core, i have a web api where i build an archive (zip) file that i return to angular, and start a download operation.

I'm facing two problems:

  • The first is that the archive can only be extracted using a compression software (7zip for example) but cannot be accessed through windows 10 functionality:

Error message: "windows cannot open the folder. The compressed (zipped) folder 'xx' is invalid"

The other zip files on my machine work just fine.

  • The second problem is that my code works if i return a byte array, but doesn't work when i return a memoryStream (i get some CORS error in the second case)

Here is some parts of the code i use (i will only post some relevant parts of the code) :

in Angular (6) i post like this:

this.post<T>(url, content,
   {
       headers: new HttpHeaders({ 'Accept': 'application/x-zip-compressed', 
                'Content-Type': 'application/json' }),
       observe: 'body',
       responseType: 'blob'
   }
)

in the ASP.NET core api:

// In the Controller
// init some variables and stuff..
var fileName...
var paths..  // a list of paths to my files

new FileExtensionContentTypeProvider().TryGetContentType(fileName, out contentType);
return File(FileService.ZipFiles(paths).ToArray(), contentType, fileName);
// here, note that contentType would be 'application/x-zip-compressed'. also note the ToArray()

and in the file service, i do the following:

using (var zipMemoryStream = new MemoryStream())
{
    var zipArchive = new ZipArchive(zipMemoryStream, ZipArchiveMode.Create);
    foreach (var path in filePaths)
    {
        // some checks on file existance here..


        ZipArchiveEntry entry = zipArchive.CreateEntry(Path.GetFileName(path));
        using (var entryStream = entry.Open())
        using (var fileStream = File.Open(path, FileMode.Open, FileAccess.Read))
        {
            fileStream.CopyTo(entryStream);
        }
    }

    zipMemoryStream.Position = 0;

    // here i return the memory stream, but i have to convert it to a byte 
    // array in the return of the controller above for it to work
    return zipMemoryStream;
}

Edit:

When analysing the file using 7zip, it says as an error:

unexpected end of data
Doe Queue
  • 51
  • 6
  • You very likely don’t want to dispose the memory stream (i.e. wrap it in a `using`) when you actually want to return it from your service. – poke Aug 08 '18 at 07:41

1 Answers1

2

Solved using the answer provided in this SO question:

ZipArchive gives Unexpected end of data corrupted error

Basically, i had to change the portion of FileService code (that i provided in the question) to this:

using (var zipMemoryStream = new MemoryStream())
{
    //  --> put the zip archive in a using block
    using(var zipArchive = new ZipArchive(zipMemoryStream, ZipArchiveMode.Create))
    {
        foreach (var path in filePaths)
        {
            // some checks on file existance here..


            ZipArchiveEntry entry = zipArchive.CreateEntry(Path.GetFileName(path));
            using (var entryStream = entry.Open())
            using (var fileStream = File.Open(path, FileMode.Open, FileAccess.Read))
            {
                fileStream.CopyTo(entryStream);
            }
        }
    }

    // --> return a byte array AFTER the using block of the zipArchive
    return zipMemoryStream.ToArray();
}

(i used the // --> to show the edited parts of the code)

Doe Queue
  • 51
  • 6
  • You saved the day I also needed `leaveOpen: true` to keep `MemoryStream` open after disposing the `ZipArchive` – Fabio Jan 27 '21 at 12:18