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?
CodePudding user response:
What I always do first in such cases is to open the "corrupt" file in a text viewer and figure out if the supposedly (file type) file is actually a (file type) file. It often turned out that it's not. E.g. when viewing a regular ZIP archive, the first 2 characters must be "PK", the rest of the file is binary "gibberish". Similar for PDFs: the first few chars are "%PDF-(PDF version)", e.g. "%PDF-1.7".
Especially with downloads, you might end up with something different than you expect, e.g. right-clicking a file link -> "Save as". Turns out, it's not a direct link to a file, but some kind of script that pushes the actual file to the client. What you get when you "Save as" that link, is the HTML output from the script, not the file itself.
There's also lots of anti-malware software monitoring web traffic and replacing suspect file with something else.
You might have "fallen prey" to something the like.
CodePudding user response:
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.