Home > Back-end >  VB.NEt cannot stream/download zip file to client
VB.NEt cannot stream/download zip file to client

Time:11-27

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.

  • Related