I have a PDF string list with strings in the form of "http://whatever.pdf" and need to create a zip file of them and stream it to client as a download.
The weird thing is if I create the zip (I'm using ZipOutputStream) and write the file to disk it works, I'm able to open the generated zip file and uncompress it with no problem, but if I stream it (what I need to do) I get a zip file of the same size but which does error when trying to open it.
CreateZip:
Private Function CreateZip(pdfPathList As List(Of String), fileRoot As String) As String
Response.Clear()
Response.BufferOutput = False
Response.ContentType = "application/zip"
Response.AddHeader("content-disposition", "attachment; filename=pdf.zip")
Dim pdfPathListLocal As List(Of String) = Utility.DownloadFilesFromList(pdfPathList, fileRoot)
Dim outputMemStream = Utility.GenerateZipOutpuStream(pdfPathListLocal)
Dim zipName As String = Guid.NewGuid.ToString() & ".zip"
outputMemStream.Position = 0
'Utility.WriteMemoryStreamToDisk(outputMemStream, fileRoot & "\" & zipName) => This line creates a valid zip file on disk, but I need to avoid it.
Response.AddHeader("Content-Length", outputMemStream.Length)
Response.Write(outputMemStream) => Writes the file ok in downloads, but apparently corrupted.
Return zipName
End Function
DownloadFilesFromList:
Public Shared Function DownloadFilesFromList(pdfPathList As List(Of String), fileRoot As String) As List(Of String)
Dim pdfPathListLocal As New List(Of String)
Dim Client As WebClient = New WebClient()
For Each strFile In pdfPathList
Dim sFile As String = Path.GetFileName(strFile)
Dim localFile As String = fileRoot + "\" + sFile
Client.DownloadFile(strFile, localFile)
pdfPathListLocal.Add(localFile)
Next
Return pdfPathListLocal
End Function
GenerateZipOutpuStream:
Public Shared Function GenerateZipOutpuStream(pdfPathListLocal As List(Of String)) As MemoryStream
Dim outputMemStream = New MemoryStream()
Dim strmZipOutputStream = New ZipOutputStream(outputMemStream)
strmZipOutputStream.SetLevel(9)
Dim objCrc32 As New Crc32()
For Each strFile In pdfPathListLocal
Dim strmFile As FileStream = IO.File.OpenRead(strFile)
Dim abyBuffer(Convert.ToInt32(strmFile.Length - 1)) As Byte
strmFile.Read(abyBuffer, 0, abyBuffer.Length)
Dim sFile As String = Path.GetFileName(strFile)
Dim theEntry As ZipEntry = New ZipEntry(sFile)
theEntry.DateTime = DateTime.Now
theEntry.Size = strmFile.Length
strmFile.Close()
objCrc32.Reset()
objCrc32.Update(abyBuffer)
theEntry.Crc = objCrc32.Value
strmZipOutputStream.PutNextEntry(theEntry)
strmZipOutputStream.Write(abyBuffer, 0, abyBuffer.Length)
'IO.File.Delete(strFile)
Next
strmZipOutputStream.Finish()
Return outputMemStream
End Function
WriteMemoryStreamToDisk:
Public Shared Sub WriteMemoryStreamToDisk(outputMemStream As MemoryStream, file As String)
Dim buffer As Byte() = outputMemStream.ToArray()
Dim ms As New MemoryStream(buffer)
Dim newFile As New FileStream(file, FileMode.Create, FileAccess.Write)
ms.WriteTo(newFile)
newFile.Close()
ms.Close()
End Sub
What may be wrong? Any help?
OK, as I've finally found the root of my issue, I'll answer myself and I hope to be helpful to anyone else facing the same problem.
The problem resides in the way aspx "UpdatePanel" works, it does a partial postback, that is not compatible con Response object and prevents it to work correctly.
The solution is to disable partial postback for the specific element causing the issue, in my case:
Adding this will cause aDownloadPdfs link to do a full postback and all Response object methods will work as expected.