PDF Binary instead of Viewer - asp.net

In an application we have here we create an advice booklet pdf's for users on a web app. These are quite hefty documents and take upto 30 seconds to generate. We decided the best method for this was to generate the pdf in the background of the application before the user requests it.
If the user requests the PDF a page is opened that checks if the booklet is complete and when it is displays it to the user.
This works great in every case unless adobe has been set to NOT 'Display PDF in browser' and the user is using IE8 or IE7.
In this case we get a warning message about a download file and the file is displayed as Binary text.
We pull the pdf when the application triggers an ajax call that generates that pushes the content using the following code.
To loop until the booklet is ready.
If pdfState = PdfBooklet.Status.Complete Then
If Me.SupportsScript Then
' Send signal back to Ajax call saying we're ready
Response.ClearContent()
Response.Write("complete")
Response.End()
Else
' Non-JS can just have it delivered straight away
pdf = CType(HttpContext.Current.Session(PdfBooklet.sSessionBookletKey), Byte())
ServerPDFBooklet(pdf)
End If
Else
' Not finished yet
Response.ClearContent()
If Me.SupportsScript Then
If isAjaxRequest Then
' Signal back to Ajax to wait a bit long
Response.Write("waiting")
Response.End()
End If
Else
' Non-JS => page refresh
Response.AddHeader("refresh", "3")
End If
End If
And to write the pdf
With Response
.Clear()
.ClearHeaders()
.AddHeader("Content-Disposition", "inline; filename=" & pdfFilename & ".pdf")
.ContentType = "application/pdf"
Try
.BinaryWrite(binaryPDF)
.Flush()
.End()
Catch Ex As HttpException When Ex.ErrorCode = &H80072746
'Client disconnected
End Try
End With
The easy way for us to fix this is to just response.redirect to a new page to serve the booklet when its complete but we would rather not do this.
Any ideas...?

Related

ASP.NET how to return pdf file as response without changing response header

I want to return a pdf file as response to some button click.
I succeeded to send the pdf file, but when i try to save it via the browser, it won't let me save it as a .pdf file (but as .aspx file)
here's the code:
Dim myWebClient As WebClient = New WebClient()
Dim myDataBuffer As Byte() = myWebClient.DownloadData(LocalImageURL) ' LocalImageURL is some path to a pdf file
Response.ContentType = "application/pdf"
Response.BinaryWrite(myDataBuffer)
Response.Flush()
Response.End()
if I am adding also the following line before writing the byte array:
Response.AddHeader("content-disposition", "attachment;filename=report.pdf")
it does the trick, but the problem is that the page remains stuck (looks like it still waits for server response to come)
This has been asked and answered before. Details are at the link below:
asp.net VB.net file download handler not work properly

Generating and downloading an `Excel` document breaks `ASP.net` LoginStatus

In my ASP.net web application I have a page which shows a (not very complicated) table. I have implemented a button so when the (registered) members clicks on it, the browser downloads the table as an Excel document
The code to generate this Excel is as follow:
Dim response As HttpResponse = HttpContext.Current.Response
' first let's clean up the response.object
response.Clear()
response.Charset = ""
Dim filename As String = MapPath("~/ex1.xls")
' set the response mime type for excel
response.ContentType = "application/vnd.ms-excel"
response.AddHeader("Content-Disposition", "attachment;filename=""" & filename & """")
' create a string writer
Using sw As New StringWriter()
Using htw As New HtmlTextWriter(sw)
' instantiate a datagrid
Dim dg As New DataGrid()
dg.DataSource = dt
dg.DataBind()
dg.RenderControl(htw)
response.Write(sw.ToString())
response.[End]()
End Using
End Using
The problem is that this code is breaking somehow the ASPN.net LoginStatus as when you try to log out after downloading this Excel (the "log out" buttom is always visible at the application) every click on the buttom will download the same Excelover and over (once per click). If you reload window or change page the "log out" will work again.
this is the "log out" link when inspecting it with chrome:
<a id="ctl00_ctl00_MainContent_LoginStatus1" href="javascript:__doPostBack('ctl00$ctl00$MainContent$LoginStatus1$ctl00','')">Log Out</a>
I have tried to make the Excel to download from other page using:
onclick="window.document.forms[0].target='_blank';"
and now it opens a new tab, download the Excel, close the tab (fast process) but still keeps breaking the logout link.
And I run out of ideas, any help, code, hint or whatever possible solution to fix this problem is very welcome.
Open a new page within the blank target, and let the new page generate the excel
This looks like a server side error.
Your code to logout actually runs the code to download Excel.
May be you should throw in a 'Response.End();' in the click handler for logout.
Well a quick work around would be to use report viewer control, which has an export to excel functionality.
I know this solution is not exactly what you were looking for, but from my experience when a user is looking for excel functionality, instead of providing a table/gridview results to the user i provide an rdlc report, which has all the export functionality.

Display Xml document in Browser vb.net

I need to render a xml document in either an new asp.net page or a pop up page.
I am following the article
I am getting the following error "Thread was being aborted." but the xml document is rendered in the page.
is there any better example
Try
If Not String.IsNullOrEmpty(tempFilePath) Then
Response.Clear()
Response.Buffer = True
Response.Charset = ""
Response.Cache.SetCacheability(HttpCacheability.NoCache)
Response.ContentType = "application/xml"
'Response.WriteFile(Server.MapPath(tempFilePath)) ' Todo Change path to temp location and add th
Response.WriteFile("c:\Test.xml")
Response.Flush()
Response.[End]()
End If
Catch ex As Exception
'TODO
Throw ex
End Try
Response.End explicitly throws that exception as result of aborting the current thread (Is Response.End() considered harmful?) - so if you are logging all exceptions or just watching in debugger you'll see ThreadAbortException.
To stop sending extra content you can follow recommendation in linked question (C#):
Response.Flush();
Response.SuppressContent = True
HttpContext.Current.ApplicationInstance.CompleteRequest()
Based on your comment you are trying to render XML as part of the same response as main HTML of the page and it is not really possible (at least end result will not be "downloadable file"). It is generally easier to serve files from separate handler that does not have any HTML rendering associated.

DotNetZip download works in one site, not another

EDIT - RESOLVED: the difference was that in the "main" case the download was initiated via a callback cycle, and in the "test" case it was initiated through a server side button click function. My guess is that the download request and the callback cycle interfered with each other, both stopping the download and causing the page to become inactive (as described below). When I rewired the download on the main page to start with a submit instead of a callback, it did initiate the download.
This is in VS2013 Ultimate, Win7Pro, VB.Net, websites (not projects),IISExpress.
I built a test site to develop functionality for creating OpenXML PPTX and XLSX memorystreams and zipping and downloading them using DotNetZip. Got it to work fine. I then merged all that code into my "main" site. Both sites are on the same machine; I can run the test site and the main site at the same time. The main site processing is somewhat more complicated, but only in terms of accessing and downloading more files.
However, the Zip and Download function (below) works fine in the test site, but the exact same code doesn't work in the main site (with or without the test site up and running).
There's an error trap (see below) around the Zip.Save function where the download occurs but no error shows up.
Same overall behavior in Chrome, Firefox and IE11.
One peculiarity that might be a clue is that when the main site download fails, the server side functionality "goes dead". Local JS functions work, but the app doesn't respond to callbacks. When I do an F5 on the browser it works again.
I did a refresh on the DotNetZip package in the main site. The Zip object appears to be working properly, because it generates an error on duplicate file names.
I thought it might be the download function as written, however, it works in the test site. Also, another piece of the main site does a non-zipped download of a memory stream (included as the second code block below) and that works fine.
I thought it might be the data. So I kludged the main site to access, convert to memorystream and download the same file that the is accessed and downloaded in the test site. Still the main site download doesn't work.
When I compare the watch values on the Zip object in the two sites, they look identical. The length of the wrkFS.ContentStream is identical in both cases. The file names are different, however, they are:
Test_2EFVG1THK5.xlsx (main)
6-18_12-46-28_0.xlsx (test)
which are both legal file names.
EDIT: I saved the zip file to disk from the main program, instead of trying to download it, using this:
wrkFilePath = "D:\filepath\test.zip"
wrkZip.Save(wrkFilePath)
And it worked fine. So that possibly isolates the problem to this statement
wrkZip.Save(context.Response.OutputStream)
EDIT: Base on help I received here:
Convert DotNetZip ZipFile to byte array
I used this construct:
Dim ms as New MemoryStream
wrkZip.Save(ms)
wrkBytes = ms.ToArray()
context.Response.BinaryWrite(wrkByteAr)
to get around the ZipFile.Save(to context), and that didn't work either; no download, no error message, and page goes dead. However, at least I can now assume it's not a problem with the ZipFile.Save.
At this point I'm out of ways to diagnose the problem.
Any suggestions would be appreciated.
Here is the code that works in the test site but not in the main site.
Public Sub ZipAndDownloadMemoryStreams(ByVal context As HttpContext) _
Implements IHttpHandler.ProcessRequest
Dim rtn As String = ""
Try
Dim wrkAr As ArrayList
wrkAr = SC.ContentArrayForDownLoad
If wrkAr.Count = 0 Then
Dim wrkStop As Integer = 0
Exit Sub
End If
Dim wrkFS As ZipDownloadContentPair
Using wrkZip As New ZipFile
'----- create zip, add memory stream----------
For n As Integer = 0 To wrkAr.Count - 1
wrkFS = wrkAr(n)
wrkZip.AddEntry(wrkFS.FileName, wrkFS.ContentStream)
Next
context.Response.Clear()
context.Response.ContentType = "application/force-download"
context.Response.AddHeader( _
"content-disposition", _
"attachment; filename=" & "_XYZ_Export.zip")
'---- save context (initiate download)-----
wrkZip.Save(context.Response.OutputStream)
wrkZip.Dispose()
End Using
Catch ex As Exception
Dim exmsg As String = ex.Message
Dim wrkStop As String = ""
End Try
End Sub
Below is the non-zip download function that works fine in the main site.
It might be possible to convert the Zip content to a byte array and try the download that way, however, I'm not sure how that would work.
(SEE EDIT NOTE ABOVE --- I implemented a version of the below, i.e. try to download byte array instead of directly ZipFile.Save(), however, it didn't help; still doesn't download, and still doesn't give any error message)
Public Sub DownloadEncryptedMemoryStream(ByVal context As HttpContext) _
Implements IHttpHandler.ProcessRequest
Dim wrkMemoryStream As New System.IO.MemoryStream()
wrkMemoryStream = SC.ContentForDownload
Dim wrkFileName As String = SC.ExportEncryptedFileName
wrkMemoryStream.Position = 0
Dim wrkBytesInStream As Byte() = New Byte(wrkMemoryStream.Length - 1) {}
wrkMemoryStream.Read(wrkBytesInStream, 0, CInt(wrkMemoryStream.Length))
Dim wrkStr As String = ""
wrkStr = Encoding.UTF8.GetString(wrkMemoryStream.ToArray())
wrkMemoryStream.Close()
context.Response.Clear()
context.Response.ContentType = "application/force-download"
context.Response.AddHeader("content-disposition", "attachment; filename=" & wrkFileName)
context.Response.BinaryWrite(wrkBytesInStream)
wrkBytesInStream = Nothing
context.Response.End()
(Per the note now at the top of the question): The difference was that in the "main" case the download was initiated via a callback cycle, and in the "test" case it was initiated through a server side button click function. My guess is that the download request and the callback cycle interfered with each other, both stopping the download and causing the page to become inactive (as described below). When I rewired the download on the main page to start with a submit instead of a callback, it did initiate the download.

Output XML as file in ASP.NET

I'm having difficulty sending an XML stream to the client browser. I've researched this considerably and everything looks right - moreover, similar code works in a previous version of this app. Any ideas what I could be doing wrong?
The following code throws no errors, but does not download a file on the client machine.
Public Shared Sub Export(ByVal source As DataTable)
Try
With Current.Response
Dim xml As String = CreateExcelXMLFromDataTable(source.DefaultView)
.Clear()
.Buffer = True
.ContentType = "application/vnd.ms-excel"
.AddHeader("Content-Disposition", String.Concat("attachment;filename=", "export.xlsx", ";"))
.AddHeader("Content-Length", xml.Length.ToString)
.Charset = ""
.Write(xml)
.Flush()
.Close()
End With
Catch ex As Exception
Console.WriteLine(ex.Message.ToString)
End Try
End Sub
Thanks!
If you are calling this function in an Ajax request it will not work. You have to cause a full postback to send the file to the client.
You can send the file without causing a full postback in the current page using an popup window (window.open) or an iframe with the URL of the download asp.net page, which will call the Export function.

Resources