Let’s say you want to have an API that will provide zip files based on some sort of information provided by the user which is stored in some blobs.
And the API is located in a remote server which you don’t want to create temporary folders.
For this matter we are gonna use mainly:
- Memory stream
- Zip archive ( introduced in .NET 4.5 )
Let’s start by downloading the information from a remote location and transform it into an array of bytes which we are gonna use later. There are two ways to retrieve the information ( synchronously or asynchronously ).
In my case I went for the asynchronous because I needed to download multiples files and add them into the same zip.
Below there are examples on each of the cases.
In the asynchronous method you will receive a stream of information in an asynchronous way where in the sync method you will receive a Web Response class with the content of the response. After receiving the response it is necessary to transform the response into a stream.
The Memory Stream is the choice here in order to have the information in memory instead of a file. It’s main purpose it is hold the content retrived in the first place. Finally we send back to the main function as bytes to be used further down.
Beware hold for the copyToAsync to finish passing the information from one Stream into another or there will be corrupted files.
Case 1: The file you request is already a zip
In some cases the bytes retrieved above are already a zip archive. In that case you can just transform those into a HttpResponseMessage with the zip attachment.
Create a memory stream with the bytes to be passed into the Stream content. Set the content type of the response as an application/zip and set the content disposition as attachment. The response will return the zip back.
Case 2: Zip with Multiple files
In the cases where there is the need to create a zip with other files or zips inside. The solution to this problem can be as follows:
- Download all the files that will compose the zip
- Wait for the download to finish on all of them
- Create a main memory stream and ZipArchive that will contain all the files
- Iterate through the files and copy each entry of bytes into the ZipArchive.
- transform the main stream into bytes
- with the bytes create the response.
It is important to hold for all the files to be downloaded because it will can be problematic to have multiple access into the same zip archive.
For each item in the new zip it is needed its associated ZipArchiveEntry and a stream to be thegate between the bytes of the file and the StreamWriter of each created entry.
In the following code I have an innerMs stream which I use to copy to the entryStream.
Don’t forget to close the stream if in any case you activated the option to leave it open.
The following code gives an idea on the logic explained above.
I prefer to use an memory stream for each task I do but in some cases you can use the same memory stream to create the response for example and long you update the position of the stream to its initial position in the stream.
ms.Position = 0
One last thing
Memory stream has an maximum capacity when you reach on its maximum capacity you will get an OutOfMemoryException. For more information check this response.
There are very good Dlls that can help fasten your features so take a look at those too.
Feel free to add question or critiscism.