Clearing a Response in Postback to download text file from Button Click - asp.net

Now... I could do this is a separate page, but i don't want to!
I am trying to create a service which fetches a load of JS files required for a project, compresses them and downloads a single file, but what it does isn't really the issue, the downloading bit is not behaving as expected.
From many examples on here, including:
In ASP.NET, how to get the browser to download string content into a file? (C#)
I have the (simplified) code:
Sub Download() Handles button.click
var AllTheScript as string ="blah blah blah"
Response.Buffer = True
Response.Clear()
Response.ClearContent()
Response.Write(AllTheScript)
Response.ContentType = "application/text"
Response.AddHeader("content-disposition", "attachment; filename=myJavascript.js")
Response.Flush()
End Sub
Obviously, I also have an <asp:button id="button" runat="server"/> element in my page.
When I click this button, it does all the fetch work (not illustrated above) creates the text file and downloads it... excellent...
Except, at the bottom of the JS file it downloads myJavascript.js it has all the markup from the page in which the button was.
I was under the impression that Response.ClearContent() should remove all this?
What am I doing wrong? Or does this have to be a separate page?

In case anyone else comes across this issue again, I solved the problem, very simple!
All it needed was
Response.End()
At the end!
So the full function becomes:
Sub Download() Handles button.click
var AllTheScript as string ="blah blah blah"
Response.Buffer = True
Response.Clear()
Response.ClearContent()
Response.Write(AllTheScript)
Response.ContentType = "application/text"
Response.AddHeader("content-disposition", "attachment; filename=myJavascript.js")
Response.Flush()
Response.End() '///<<< Final Line Essential!
End Sub

Try this
var context = HttpContext.Current;
context.Response.Clear();
context.Response.ClearHeaders();
context.Response.ClearContent();
////
context.Response.AddHeader("content-disposition", "attachment; filename=myJavascript.js");
content.Response.Write(AllTheScript);

Related

Download PDF using Response on ASPX Page only working in Page_Load

I've seen several questions relating to downloading a PDF from a Web browser using Response, but none seem to fit the mysterious issue I'm having.
I am working on a project that requires the user to be able to click a button (btnPDF) to instantly download a PDF of a Telerik report with a specific "ID" string to the Downloads folder. This process was originally located in an ASPX Page on an IIS separate from where the button is located. When btnPDF was clicked, I used Response.Redirect to download the PDF through that page. The code to download the PDF looked like this:
Response.Clear()
Response.ContentType = result.MimeType 'this is always "application/pdf"
Response.Cache.SetCacheability(HttpCacheability.Private)
Response.Expires = -1
Response.Buffer = True
Response.AddHeader("Content-Disposition", String.Format("{0};FileName={1}", "attachment", fileName))
Response.BinaryWrite(result.DocumentBytes)
Response.End()
Note that result.DocumentBytes is a byte array containing correct bytes for the PDF.
This code worked fine. Now, instead of having the process on a separate Page in a separate project, I need to merge the process onto the same page where btnPDFis located, so that when you click btnPDF, a subroutine is called that performs the same task. I thought this would be very easy, pretty much a copy and paste. With the same code added in a new subroutine, this is what my click event handler "ButtonPDF_Click" now looks like:
Protected Sub ButtonPDF_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnPDF.Click
DownloadReportPDF(Me.RadGrid1.SelectedValue.ToString())
Dim strMessage As String = "alert('Printed PDF Sheet.');"
ScriptManager.RegisterStartupScript(Me, Me.GetType, "MyScript", strMessage, True)
End Sub
Protected Sub DownloadReportPDF(ByVal releaseMasterId As String)
'Service call to generate report source
Dim service As New TelerikReportLibrary.ReportServices.PPSReportService
Dim source As Telerik.Reporting.TypeReportSource = service.GetReportSource(releaseMasterId)
'Render PDF and download
Dim reportProcessor As New ReportProcessor()
Dim result As RenderingResult = reportProcessor.RenderReport("PDF", source, Nothing)
Dim fileName As String = result.DocumentName + "_" + releaseMasterId + "." + result.Extension
Response.Clear()
Response.ContentType = result.MimeType 'this is always "application/pdf"
Response.Cache.SetCacheability(HttpCacheability.Private)
Response.Expires = -1
Response.Buffer = True
Response.AddHeader("Content-Disposition", String.Format("{0};FileName={1}", "attachment", fileName))
Response.BinaryWrite(result.DocumentBytes)
Response.End()
End Sub
But the PDF no longer downloads. An accurate byte array is still created, but the Response portion does not result in the PDF being downloaded from the browser. I've found that putting a call to DownloadReportPDF in the Page_Load handler on the same Page successfully generates and downloads a PDF as it did before.
I can't see any reason why this isn't working, but I'm new to ASP, and I'm not great in VB. I've tried using Response.OutputStream, Response.WriteFile, and making use of a MemoryStream, among several other things that I've lost track of. I'm hoping there's something simple, maybe some sort of property of the Page or btnPDF I could be missing. Here is the markup for btnPDF, just in case:
<asp:linkButton ID="btnPDF" CssClass="btn btn-default" runat="server" Width="115px">
<i class="fa fa-file-text" title="Edit"></i> PDF
</asp:linkButton>
What could be causing such a problem? Where should I look at this point?
Let me know if more information is needed.
Thanks,
Shane
EDIT:
I experimented with setting a session variable on btnPDF_Click, and handling the PDF download on postback. Again, a valid byte array was generated, but the HttpResponse did not cause the PDF to download from the browser.
EDIT:
Building on the last edit, this tells me that calling DownloadReportPDF from Page_Load works only when IsPostBack is false. I just tested this thought, and it holds true. In the above code, if I check IsPostBack at the moment I'm trying to download the PDF, it is true. Investigating further.
Alright, I finally found a solution I'm satisfied with (though I still don't understand why I can't download the PDF using Response while IsPostBack is true).
Inspired by this thread, I put the previously posted code in an HttpHandler called PDFDownloadHandler, then used Response.Redirect in the btnPDF_Click event handler to utilize PDFDownloadHandler. This article helped me a lot on that process, as it is something I have not done before.
In case anyone else runs into this problem, here is the new PDFDownloadHandler:
Imports Microsoft.VisualBasic
Imports System.Web
Imports Telerik.Reporting
Imports Telerik.Reporting.Processing
Public Class PDFDownloadHandler
Implements IHttpHandler
Public Sub ProcessRequest(ByVal context As _
System.Web.HttpContext) Implements _
System.Web.IHttpHandler.ProcessRequest
Dim request As HttpRequest = context.Request
Dim response As HttpResponse = context.Response
Dim path As String = request.Path
If path.Contains("pps.pdfdownload") Then
Dim releaseMasterId As String = request.QueryString("ID")
If releaseMasterId IsNot Nothing Then
'Service call to generate report source
Dim service As New TelerikReportLibrary.ReportServices.PPSReportService
Dim source As Telerik.Reporting.TypeReportSource = service.GetReportSource(releaseMasterId)
'Render PDF and save
Dim reportProcessor As New ReportProcessor()
Dim result As RenderingResult = reportProcessor.RenderReport("PDF", source, Nothing)
Dim fileName As String = result.DocumentName + "_" + releaseMasterId + "." + result.Extension
response.Clear()
response.ContentType = result.MimeType
response.Cache.SetCacheability(HttpCacheability.Private)
response.Expires = -1
response.Buffer = True
response.AddHeader("Content-Disposition", String.Format("{0};FileName={1}", "attachment", fileName))
response.BinaryWrite(result.DocumentBytes)
End If
End If
response.End()
End Sub
Public ReadOnly Property IsReusable() As Boolean _
Implements System.Web.IHttpHandler.IsReusable
Get
Return False
End Get
End Property
End Class
Any further insight on why the original technique did not work is greatly appreciated.

IE11 writes HTML in Response.BinaryWrite instead of byte() content

I have an ASP.NET (Framework 2.0) website which generates a CSV file and propmpts the user to Save or Open this file (IE native pop-up window). Recently some users upgraded their IE to version 11 and they get the file with HTML as content and not the actual CSV-style rows.
This is working in IE9 and below.
Code for Response.BinaryWrite:
Response.Buffer = False
Response.ClearContent()
Response.ClearHeaders()
Response.ContentType = "application/octet-stream"
Response.AddHeader("Content-Disposition", "attachment;filename=FileExport.csv")
Response.BinaryWrite(Session("nExport"))
Session("nExport") = Nothing
Response.Flush()
Response.Close()
Response.End()
' Session("nExport") contains Byte()
Expected file content:
NR;FirstName;LastName
1;Bilbo;Baggins
File content if I select Save or Open:
"<!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Transitional//EN"" ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"">"
"<html xmlns=""http://www.w3.org/1999/xhtml"" >"
<head><title>
" Export"
</title></head>
<body>
" <form name=""form1"" method=""post"" action=""nExport.aspx?ID=RGVwbjsu3GFyamkyMDEz"" id=""form1"">"
<div>
"<input type=""hidden"" name=""__VIEWSTATE"" id=""__VIEWSTATE"" value=""/wEPDwUJNzgzNDMwNTMzZGSmoL1exQ/68hIbp0DWxDDjlt6wAA=="" />"
</div>
<div>
</div>
</form>
</body>
</html>
Edit: additional information from the user is that another (similar) CSV file download is working correctly. I will have to investigate some more, code for both downloads is the same.
Edit 2:
It seems to be working on UAT server, the solution was removing Response.End and Response.Close and use HttpApplication.CompleteRequest, as per this question ie-10-file-download-issues. Will have to investigate more and try on production servers.
Dim httpApp As New HttpApplication
httpApp.CompleteRequest()
'Response.Close()
'Response.End()
I can confirm a working solution on the production server also. As the comment from stun in this answer suggests I left Response.Close and Response.End after CompleteRequest.
This is the new Response method:
Response.Buffer = False
Response.ClearContent()
Response.ClearHeaders()
Response.ContentType = "application/octet-stream"
Response.AddHeader("Content-Disposition", "attachment;filename=FileExport.csv")
Response.BinaryWrite(Session("nExport"))
Session("nExport") = Nothing
Response.Flush()
HttpContext.Current.ApplicationInstance.CompleteRequest()
Response.Close()
Response.End()
Edit: just a fix, using HttpContext.Current not making a new HttpApplication.

ASP.NET Downloadable Image Files?

I don't have apache support on this website, but I need to be able to allow images to be downloadable in a certain directory only. How can I do this? This site only has ASP.NET support, and it's killing me! Noticed this link: How to download files in mvc3? but not sure where to put that code at, or even if that code there would help me any.
Any help would be greatly appreciated! A Starting point or something...
Is there a way I can just do this in HTML? Like, for example, set the download link to point to an html file, where the HTML file grabs the image file and makes it downloadable, in and of itself?
So far I have the following ASP code in a file called: default.asp
Which begins the download just fine, but it downloads an empty file (download.jpg). How can I point the following code to an actual image file to download?
<%# Language=VBScript %>
<% Option Explicit
Response.ContentType = "application/octet-stream"
Response.AddHeader "Content-Disposition", "attachment; filename=" + "download.jpg"
%>
I have a file named, "download.jpg" even within the same directory, but it never downloads the actual image. It downloads a 90 byte empty image file instead.
I even tried this with no luck:
<%# Language=VBScript %>
<% Option Explicit
Response.ContentType = "application/octet-stream"
Response.AddHeader "Content-Disposition","attachment; filename=07awardee.png"
Response.TransmitFile Server.MapPath("~/images/07awardee.png")
Response.End
%>
And yes, I have the 07awardee.png file in images/07awardee.png on the server root and even in the folder root where default.asp is located. Arggg! What gives here? The file is a bit bigger now at 392 bytes, but it still isn't readable as an image file... I've been searching the internet and this is supposed to work, but doesn't! What could be the problem here?
Your .aspx page with a Request.End throws a ThreadAbortException, and that's bad for server performance (too many of these can even crash a server). So you'll want to avoid that. http://weblogs.asp.net/hajan/archive/2010/09/26/why-not-to-use-httpresponse-close-and-httpresponse-end.aspx
The way I handle this problem is with a HttpHandler (.ashx) and use that to serve downloadable image files. I used some of your code because my implementation was in C# and has much more code (includes image scaling options etc):
//<%# WebHandler Language="VB" Class="DownloadImage" %> // uncomment this line!
Public Class DownloadImage : Implements IHttpHandler
Protected EnabledTypes() As String = New String() {".jpg", ".gif", ".png"}
Public Sub ProcessRequest(ByVal context As HttpContext) _
Implements IHttpHandler.ProcessRequest
Dim request = context.Request
If Not String.IsNullOrEmpty(request.QueryString("file")) Then
Dim path As String = context.Server.MapPath(request.QueryString("file"))
Dim file As System.IO.FileInfo = New System.IO.FileInfo(path)
If file.Exists And EnabledTypes.Contains(file.Extension.ToLower()) Then
context.Response.Clear()
context.Response.AddHeader("Content-Disposition", _
"attachment; filename=" & file.Name)
context.Response.AddHeader("Content-Length", file.Length.ToString())
context.Response.ContentType = "application/octet-stream"
context.Response.WriteFile(file.FullName)
Else
context.Response.ContentType = "plain/text"
context.Response.Write("This file does not exist.")
End If
Else
context.Response.Write("Please provide a file to download.")
End If
End Sub
Public ReadOnly Property IsReusable() As Boolean _
Implements IHttpHandler.IsReusable
Get
Return True
End Get
End Property
End Class
Make sure you implement a check for image files, otherwise you have a potential security problem. (Users could download web.config where database passwords are stored)
The link would become:
Download image
You should clear the header and provide the correct header and content type
Response.Clear()
Response.AppendHeader("Content-Disposition", "attachment; filename=somefilename")
Response.ContentType = "image/jpeg"
Response.TransmitFile(Server.MapPath("/xyz.jpg"));
Response.End();
OMG, I rock. Here's the way this is done. Create a file called, download.aspx, and input the following code into it:
<%# Page language="vb" runat="server" explicit="true" strict="true" %>
<script language="vb" runat="server">
Sub Page_Load(Sender As Object, E As EventArgs)
Dim strRequest As String = Request.QueryString("file")
If strRequest <> "" AND strRequest.EndsWith(".jpg") OR strRequest.EndsWith(".jpeg") OR strRequest.EndsWith(".png") OR strRequest.EndsWith(".gif") OR strRequest.EndsWith(".pdf") OR strRequest.EndsWith(".doc") OR strRequest.EndsWith(".docx") OR strRequest.EndsWith(".bmp") Then
Dim path As String = Server.MapPath(strRequest)
Dim file As System.IO.FileInfo = New System.IO.FileInfo(path)
If file.Exists Then
Response.Clear()
Response.AddHeader("Content-Disposition", "attachment; filename=" & file.Name)
Response.AddHeader("Content-Length", file.Length.ToString())
Response.ContentType = "application/octet-stream"
Response.WriteFile(file.FullName)
Response.End
Else
Response.Write("This file does not exist.")
End If
Else
Response.Write("You do not have permission to download this file type!")
End If
End Sub
</script>
Now, when you want to get a file to download (ANY FILE), just link it like so:
Download the logo image
And that's all she wrote!

ASP.Net Update Panel with "The message received from the server could not be parsed"

Okay, I've seen this asked in a couple of spots but never really got an answer that helped or that I understood. I'm just starting back on ASP.net and am using VS 2010 on the 4.0 framework.
I found some code online to allow you to generate an .xls Excel file from a dataset.
The code is below, but when I run this code from a button outside of my ajax update panel it works perfectly. If I execute the code from a button inside the update panel (where I need it to be) then I get the following:
Sys.WebForms.PageRequestManagerParserErrorException The message received from the server could not be parsed.
I have tried the two versions of the header shown and have tried the completerequest() instead of response.end.
Could someone explain to me why this doesn't work in the update panel and how I could make it work in the update panel?
Thanks in advance!
Protected Sub ExportDataSetToExcel(ByVal ds As DataSet, ByVal filename As String)
Dim response As HttpResponse = HttpContext.Current.Response
' first let's clean up the response.object
response.Clear()
response.Charset = ""
' set the response mime type for excel
response.ContentType = "application/vnd.ms-excel"
'response.ContentType = "application/octet-stream"
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 = ds.Tables(0)
dg.DataBind()
dg.RenderControl(htw)
response.Write(sw.ToString())
'HttpContext.Current.ApplicationInstance.CompleteRequest()
response.End()
End Using
End Using
End Sub
Try this:
response.Flush();
HttpContext.Current.ApplicationInstance.CompleteRequest()
Do not call reposne.End()
check out this sample:
How to download/open the file that I retrive by server path?
it shows how to write a handler to DL a file.
Sorry, I know is a bit late, but found the answer right now.
Try with this answer. I resolve it doing what it is said here and it works perfectly

DataExport to Excel Error

Hi I am trying Export data to excel sheet from GridView but having this error.
RegisterForEventValidation can only be called during Render();
Here is my code
Dim attachment As String
attachment = "attachment; filename=Contacts.xls"
Response.ClearContent()
Response.AddHeader("content-disposition", attachment)
Response.ContentType = "application/ms-excel"
Dim myStringWriter As New IO.StringWriter
Dim myhtmlStringWriter As New HtmlTextWriter(myStringWriter)
GridView1.RenderControl(myhtmlStringWriter)
Response.Write(myStringWriter.ToString)
Response.End()
Thanks
You can do this in the web.config file but in this case the eventValidation will be turned off for all the pages.
or you can do this in the Page directive which will turn off the validation for a single page.

Resources