Capture response stream and output to file - asp.net

We are using an online pdf encoding service where we send them the raw html and they return the pdf document. We want to take the WebResponse and immediately download it as a file to their desktop. This seems so straightforward and yet I can't seem to capture the stream correctly for download. I've tried many different approaches but I always end up with a 0 byte file for download. This is my latest incarnation which has gotten overly complicated but it still doesn't work.
Dim request = DirectCast(HttpWebRequest.Create(Url), HttpWebRequest)
request.Method = "POST"
request.ContentType = "application/x-www-form-urlencoded"
request.ContentLength = byteArray.Length
Using dataStream = request.GetRequestStream()
dataStream.Write(byteArray, 0, byteArray.Length)
End Using
Try
Dim response As WebResponse = request.GetResponse
Dim bytes As Byte()
Using st As Stream = response.GetResponseStream
Dim ByteList As New ArrayList
Dim reader As New BinaryReader(st)
Dim length As Integer
While (InlineAssignHelper(bytes, reader.ReadBytes(1024))).Length > 0
ByteList.Add(bytes)
length += bytes.Length
bytes = New Byte(length - 1) {}
Dim position As Integer = 0
For Each b As Byte() In ByteList
Array.Copy(b, 0, bytes, position, b.Length)
position += b.Length
Next
End While
End Using
HttpContext.Current.Response.Clear()
HttpContext.Current.Response.AddHeader("Content-Type", "application/pdf")
HttpContext.Current.Response.AddHeader("Content-Disposition", String.Format("{0}; filename=Report Detail.pdf; size={1}", "attachment", bytes.Length.ToString()))
HttpContext.Current.Response.BinaryWrite(bytes)
HttpContext.Current.Response.Flush()
HttpContext.Current.Response.Close()
HttpContext.Current.Response.End()
Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, ByVal value As T) As T
target = value
Return value
End Function

Related

Send Excel file to Browser Asp.net

I have been breaking my head for the last two days and can't get this to work. I have a report, which I am exporting to Excel and saving on the server file directory. That part works perfectly, I can see the file, and open it, all good. The issue relies on when I try to send it to the browser for download from the server. It does not download anything, I do see the Response Header with all the info on the browser but nothing happens.
Here's one of my many tries
Private Sub dxgvPOAll_ToolbarItemClick(source As Object, e As ASPxGridViewToolbarItemClickEventArgs) Handles dxgvPOAll.ToolbarItemClick
Select Case e.Item.Name
Case "ExportAll"
Using report As DevExpress.XtraReports.UI.XtraReport = New POs_Dashboard_Report()
Using ms As New System.IO.MemoryStream()
report.Name = "Backorder Tickets"
report.ExportOptions.PrintPreview.SaveMode = DevExpress.XtraPrinting.SaveMode.UsingSaveFileDialog
Dim xlsxExportOptions As New DevExpress.XtraPrinting.XlsxExportOptions() With {.ExportMode = DevExpress.XtraPrinting.XlsxExportMode.SingleFile, .ShowGridLines = True, .FitToPrintedPageHeight = True}
Dim folderPath As String = "~/Account/TemporaryFiles/" & Utilities.RetrieveEmployeeNumber() & "/" & Guid.NewGuid.ToString & "/"
Dim serverPath As String = Server.MapPath(folderPath)
Dim xlsxExportFilePath As String = serverPath & report.Name & ".xlsx"
Dim folderInf As New DirectoryInfo(serverPath)
If Not folderInf.Exists Then folderInf.Create()
report.ExportToXlsx(xlsxExportFilePath, xlsxExportOptions)
Try
Dim objRequest As FileWebRequest = CType(WebRequest.Create(xlsxExportFilePath), FileWebRequest)
Dim objResponse As FileWebResponse = CType(objRequest.GetResponse(), FileWebResponse)
Dim bufferSize As Integer = 1
Response.Clear()
Response.ClearHeaders()
Response.ClearContent()
Response.AppendHeader("Content-Disposition:", "attachment; filename=" & xlsxExportFilePath)
Response.AppendHeader("Content-Length", objResponse.ContentLength.ToString())
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
Dim byteBuffer As Byte() = New Byte(bufferSize + 1 - 1) {}
Dim memStrm As MemoryStream = New MemoryStream(byteBuffer, True)
Dim strm As Stream = objRequest.GetResponse().GetResponseStream()
Dim bytes As Byte() = New Byte(bufferSize + 1 - 1) {}
While strm.Read(byteBuffer, 0, byteBuffer.Length) > 0
Response.BinaryWrite(memStrm.ToArray())
Response.Flush()
End While
HttpContext.Current.Response.Flush()
HttpContext.Current.Response.SuppressContent = True
HttpContext.Current.ApplicationInstance.CompleteRequest()
Catch e1 As ThreadAbortException
Catch ex As Exception
End Try
End Using
End Using
End Select
End Sub
Here's what I see on the browser's Response-Header:

Merge PDF by streams

I am in trouble with a .ashx which should merge some PDF memory-stream, in a simplest case, where I have in output only one stream, the output PDF stream are corrupted, but when I call another ashx which get in output only the single stream works, what I miss in the following code?
I collect memory-streams:
Dim streamDocument As MemoryStream = FumForm.CreatePdfDocument(context, _fumForm, _formTemplate, _match)
lReader.Add(New PdfReader(streamDocument))
then I would like append all pdf pages in an other pdf:
Dim document As Document = New Document(PageSize.A4, 0, 0, 0, 0)
Dim writer As PdfWriter = PdfWriter.GetInstance(document, context.Response.OutputStream)
document.Open()
For Each r As PdfReader In lReader
For i As Integer = 1 To r.NumberOfPages
Dim page As PdfImportedPage = writer.GetImportedPage(r, i)
document.Add(Image.GetInstance(page))
Next
Next
Dim filename = String.Format("{0}{1}.pdf", "pippo", "test")
document.Close()
context.Response.Clear()
context.Response.ContentType = "application/pdf"
context.Response.AppendHeader("content-disposition", "inline; filename=""" & filename & """")
context.Response.Flush()
context.Response.Close()
context.Response.End()
CreatePdfDocument works well, and have this signature
static public MemoryStream CreatePdfDocument(HttpContext context,
FumForm form,
FumFormTemplate formTemplate,
Match match)
Any help will be really appreciated
The code first writes the whole PDF to context.Response.OutputStream
Dim document As Document = New Document(PageSize.A4, 0, 0, 0, 0)
Dim writer As PdfWriter = PdfWriter.GetInstance(document, context.Response.OutputStream)
...
document.Close()
and thereafter clears and changes headers of the context.Response
context.Response.Clear()
context.Response.ContentType = "application/pdf"
context.Response.AppendHeader("content-disposition", "inline; filename=""" & filename & """")
To work correctly, all response object clearing and header manipulations have to be finished before the data may be written to the response stream.

How do I decide on a buffer size when downloading a file using HttpWebRequest and HttpWebResponse?

I'm using HttpWebRequest / HttpWebResponse to download an image file from a remote server to my own web server. The code is working fine, but I don't know if the buffer size I've chosen is the optimum size for best performance.
How would I go about choosing the right buffer size?
My code is below - you can see it's currently using a buffer size of 4096 - that's just an arbitrary number I chose:
' Create the web request
Dim myWebRequest As HttpWebRequest = HttpWebRequest.Create("http://www.petiquettedog.com/wp-content/uploads/2010/04/sadpug-300x225.jpg")
' Automatically decompress gzip/deflate compressed images. This line sets the Accept-Encoding header to "gzip, deflate"
myWebRequest.AutomaticDecompression = DecompressionMethods.GZip or DecompressionMethods.Deflate
Using myWebResponse As HttpWebResponse = myWebRequest.GetResponse()
' Download the image to disk
Using streamIn As Stream = myWebResponse.GetResponseStream()
Using streamOut As FileStream = File.Create(localFilePhysical)
Dim bufferSize As Integer = 4096
Dim bytes(bufferSize) As Byte
Dim numBytes As Integer
numBytes = streamIn.Read(bytes, 0, bufferSize)
While numBytes > 0
streamOut.Write(bytes, 0, numBytes)
numBytes = streamIn.Read(bytes, 0, bufferSize)
End While
End Using
End Using
End Using

Response.Redirect a download in progress

I have a website where a user can choose to view a video (no copyright) that is on a 3rd party website. From the moment the user choose it, it needs to be downloaded onto my web server before the user can access it. I tried to automatically start the download on the 3rd party website and make a response.redirect with this path, but when the user is watching the video, if the video has only 10 seconds downloaded, any player/browser will considere this video as a ten-seconds video and stop it after 10 seconds.
What would be the best practice to redirect a stream instead of a file?
I found that this piece of code is doing exactly what I want. It downloads a file on a third party website, and as it's streaming it, each chunk is writen in the Response so that it completely obsfuscates the origin. Thus, it is possible to serve any file from any website as if I own it.
Private Sub SendFile(ByVal url As String)
Dim stream As System.IO.Stream = Nothing
Dim bytesToRead As Integer = 10000
Dim buffer() As Byte = New Byte((bytesToRead) - 1) {}
Try
Dim fileReq As System.Net.WebRequest = CType(System.Net.HttpWebRequest.Create(url), System.Net.HttpWebRequest)
Dim fileResp As System.Net.HttpWebResponse = CType(fileReq.GetResponse, System.Net.HttpWebResponse)
If (fileReq.ContentLength > 0) Then
fileResp.ContentLength = fileReq.ContentLength
End If
stream = fileResp.GetResponseStream
Dim resp As System.Web.HttpResponse = HttpContext.Current.Response
resp.ContentType = "application/octet-stream"
resp.AddHeader("Content-Disposition", ("attachment; filename=\""" + ("mp3" + "\""")))
resp.AddHeader("Content-Length", fileResp.ContentLength.ToString)
Dim length As Integer = 1000000
While (length > 0)
If resp.IsClientConnected Then
length = stream.Read(buffer, 0, bytesToRead)
resp.OutputStream.Write(buffer, 0, length)
resp.Flush()
buffer = New Byte((bytesToRead) - 1) {}
Else
length = -1
End If
End While
Catch
stream.Close()
Finally
If (Not (stream) Is Nothing) Then
stream.Close()
End If
End Try
Response.End()
End Sub

Post file to ashx page on different server

I have a asp.net web site where the user chooses some files with a fileUpload Control. Then the files need to be posted to another server
My domain is [http://www.mydomain.com]
The address where i have to upload the files is something like: [https://www.externaldomain.com/upload.ashx?asd2t423eqwdq]
I have tried the following:
Dim uploadedFiles As HttpFileCollection = Request.Files
Dim userPostedFile As HttpPostedFile = uploadedFiles(0)
Dim filePath As String
filePath = "https://www.externaldomain.com/upload.ashx?asd2t423eqwdq" & "/" & userPostedFile.FileName
userPostedFile.SaveAs(filePath)
But i get an error:
The SaveAs method is configured to require a rooted path, and the path 'https://www.externaldomain.com/upload.ashx?asd2t423eqwdq/Core CSS 3.pdf' is not rooted
I searched the internet, but all i could find were examples on how to upload to the page's server.
EDIT:
I used HttpWebRequest to access the link and it partialy worked. I also need to send 2 POST parameters, username and password.
This is how my code looks like now:
Dim link As String = "https://www.externaldomain.com/upload.ashx?e9879cc77c764220ae80"
Dim req As HttpWebRequest = WebRequest.Create(link)
Dim boundary As String = "-----"
req.ContentType = "multipart/form-data; boundary=" + boundary
req.Method = "POST"
Dim username As String = "test"
Dim userpass As String = "123456"
Dim credentials() As Byte = Encoding.UTF8.GetBytes("username=" & username & "&password=" & userpass & "--\r\n" & boundary & "--\r\n")
Dim separators() As Byte = Encoding.UTF8.GetBytes("--" + boundary + "--\r\n")
Dim uploadedFiles As HttpFileCollection = Request.Files //this is where i take the file that the user wants to upload
Dim userPostedFile As HttpPostedFile = uploadedFiles(0)
//i convert the file to a byte array
Dim binaryReader As IO.BinaryReader
Dim fileBytes() As Byte
binaryReader = New BinaryReader(userPostedFile.InputStream)
fileBytes = binaryReader.ReadBytes(userPostedFile.ContentLength)
//'get the request length
req.ContentLength += credentials.Length
req.ContentLength += userPostedFile.ContentLength
req.ContentLength += separators.Length
req.ContentLength += 1
Dim dataStream As Stream
dataStream = req.GetRequestStream
dataStream.Write(credentials, 0, credentials.Length)
dataStream.Write(separators, 0, separators.Length)
dataStream.Write(fileBytes, 0, fileBytes.Length)
dataStream.Close()
Dim response As HttpWebResponse = req.GetResponse
The error i get is "forbidden". The username and password are 100% correct. I think the problem is that i do not create the request correctly. If i post only the credentials i get the error saying that i have no file...
Any ideas?
Eventually I used the code provided here http://aspnetupload.com/
I compiled it into a dll and added a reference to my solution.
It works :)

Resources