I've got a problem on a WebForms application where a user selects some criteria from drop downs on the page and hits a button on the page which calls this method:
protected void btnSearch_Click(object sender, EventArgs e)
They then click on button to download a zip file based on the criteria which calls this method:
protected void btnDownload_Click(object sender, EventArgs e)
In IE, they are prompted with the bar at the top of the browser that tells them:
"To help protect your security, Internet Explorer blocked this site
from downloading files to your computer".
When they click on that bar to download the file, it fires the btnSearch_Click event again.
Response.ContentType and Response.AddHeader has been set up correctly.
The problem is, that btnSearch appends criteria so basically it is being appended twice and causing problems.
Is there something I can do to prevent this?
This is a VS2008 web application using C# 3.5 for what it's worth.
When they click the download button, do a Redirect to the ZIP file handler (page?) to download the file. i.e. use the Post-Redirect-Get pattern: http://en.wikipedia.org/wiki/Post/Redirect/Get
Are you using the Content-Disposition header?
Response.AddHeader("Content-Disposition", "attachment; filename=fileName.zip");
Try changing the content type to match the file type?
Save a boolean value into the Session indicating that the criteria have been already appended.
When the user selects another value from the dropdowns then set this value to false.
Inside your btn_Download event you then can check the value of the Session variable and avoid setting the criteria twice.
Related
So I have a button inside my gridview. If the user clicks on the button a rowcommand is send and a pdf file is downloaded / written to the response.
Code
HttpResponse httpResponse = Response;
httpResponse.Clear();
httpResponse.ContentType = "application/pdf";
httpResponse.AddHeader("content-disposition", $"attachment;filename={rowData.Pod.fileName}");
httpResponse.Output.Write(bytes);
Response.Flush();
HttpContext.Current.ApplicationInstance.CompleteRequest();
For some reason I always get Server cannot set content type after HTTP headers have been sent. when tried to download the file. Now the gridview is in a updatepanel but that should not be a problem since other buttons for downloading work.
I have also tried to send the buffer to true before I did the file download but that did not change it.
EDIT
The problem was that there was still an async postback that I had setup on the 'selectedindexchanged' of the gridview to display a modal. Is there any way I can work around this? When I change the trigger the whole page reloads before showing the modal and also resprings. The file downloads after changing it to postback instead of asyncpostback
I had an issue that was extremely similar to this. I had a button inside a ListView control that was trying to print a pdf report. After extensive research I found a very simple solution.
Add OnInit="btnPrint_Init" to the button on the front of the page and then add the following to the code behind (change the name of the button to suit your needs):
protected void btnPrint_Init(object sender, EventArgs e)
{
Button btnPrint = (Button)sender;
ScriptManager.GetCurrent(this).RegisterPostBackControl(btnPrint);
}
Probably, Response.Buffer is false.
You should write the content after writing the headers.
httpResponse.ContentType = "application/pdf";
httpResponse.AddHeader("content-disposition", $"attachment;filename={rowData.Pod.fileName}");
httpResponse.Output.Write(bytes);
Actually, you can instead set a JavaScript command to those buttons requesting an http handler which is the best practice for downloading a file.
For security reasons you can create a guid and put the guid to session items for each row (having the file id as the value) and then send that guid to the http handler and retrieve the file id from session and response binary write the file
This is a problem I've had in the past, but I forgot if I ever solved it or not. I have it so when the user clicks on an asp:linkbutton it triggers a download for a file. File downloads successfully without a problem. However, after it downloads if the user clicks to download again or clicks a button a postback happens and the page refreshes, clearing out everything such as tables or text. How do I prevent this from happening?
Here's the code executing for the download.
string name = Path.GetFileName(filePath);
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=\"" + name + "\"");
Response.ContentType = mimeType;
Response.BinaryWrite(file);
Response.End();
NOTES:
The linkbutton control is NOT created behind the scenes in code, if that makes a difference.
The file does not download when clicking the link on the second time. Only a refresh happens.
This is part of a DNN module
First you need to save the information you want to keep before the post back happens. One of the ways this can be done is by using session. For example if you wanted to save the value of a text box you could say:
Session["TextBox1"] = TextBox1.Text;
Then you need to handle the post back in your page load function.
private void Page_Load()
{
//check if this is a post back
if(this.IsPostBack)
{
//restore your values
TextBox1.Text = (string)Session["TextBox1"];
}
}
Okay, I know the source of this problem , but I never found a solution for it. The reason this even shows up is because of a setting in DotNetNuke. Under Host Settings in the Advanced Settings tab if you look at Performance Settings there is a setting called Page State Persistence. If you set this to Memory like I did it will cause AJAX issues. It's even noted in the description. Setting it back to Page makes the problem disappear.
Reason I've kept it as memory is because my company's site was using Memory, however without my knowing it was switched back to Page. Now it's a non issue, but if anyone finds a solution for when it's set to Memory let me know! Otherwise, I'd suggest against using it unless it was fixed in newer versions of DNN.
I'm currently trying to look at a directory, and then preview a .jpeg from a list box. I have the list box populating with the contents of the directory and only showing Jpegs, but I can't think of what to do to get the jpeg preview in a picture box. I'm using an asp .net application on Visual Studio 2010.
This is the code I have
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
DirectoryInfo infoDir = new DirectoryInfo(#"G:\Test_Directory");
FileInfo[] infoFile = infoDir.GetFiles("*.jpeg");
foreach( FileInfo file in infoFile )
{
lstDirectory.Items.Add(file.Name);
}
}
protected void lstDirectory_SelectedIndexChanged(object sender, EventArgs e)
{
}
}
I'm under the understanding Postback needs to be used. If anyone is able to help, that would be great.
The file which is in the G: Drive, is a jpeg, which can be seen in the list box is : jpegimage.jpeg
Thanks.
How about something like this?
I think you could do this mostly in Javascript, with two additional ASP.NET page.
First, create a new web page. We'll call this A.aspx. This page will be passed the image name in the query string. It will be very simple: it will just fetch the contents of the file from "G:\TestDirectory" and write it to the Response stream. There are quite a few questions and answers on Stack Overflow on how to do this, if you haven't done it before.
Then, create another web page. We'll call this B.aspx. This will have an image control with height and width set appropriately. It will also take the image name from its query string. The code-behind will build a URL to use as the ImageSource property on the image control. The URL will be that of A.aspx, with the (URL-encoded) image name appended as a parameter.
On your ASP.NET page, hook up an event handler to your listbox. When the selected index on the list box changes, on the client side, build a URL, based on the URL to B.aspx with the image name from the list box appended as a parameter. Then open a window, using the URL you just built, pointing to B and passing the desired file name.
So: when the list box selected index changes (or when you double click, or whatever event you pick), the javascript will open a window with page B.aspx. Page B will have an image control, set to the URL to A.aspx. A.aspx will stream the image contents to the image control, which will appear in your new window.
There is many similar questions but there is still no clear answer that is solving the problem taking some action after writing some stream to response.
I have a following situation:
On button click I am generating some excel file that I am going to write to response allowing user to download generated file. Imidietly after clicking the button, I am disabling it, to prevent double clicking this button. In Page-Load event handler I have following code:
GenerateBTN.Attributes.Add("onclick", "this.disabled=true;" + ClientScript.GetPostBackEventReference(GenerateBTN, "").ToString());
After Page_Load eventhandler, GenerateBTN_Click handler executes the code needed for generating the file and at the end of this method (handler) I am response writing generated file with following code:
Response.Clear();
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
Response.WriteFile(#"C:\Reports\" + filename);
Response.End();
The Save As dialog appears and user can download the generated file, but the problem is that the disabled GenerateBTN remains disabled. How to enable it afer Writing generated file to response? I understand that afer clearing current response I can not continue with the initial Response, but is there any way to solve this problem?
You can put an IFrame on the page and set it's visiblity to hidden. Have your button load the file in the IFrame and use Javascript to detect if the IFrame is still loading or not. When the loading is done, enable your button.
Can't supply a code example at the moment, but if you decide to go this route and need a sample, let me know I will update this answer.
Edit for 2nd answer
What you want to do is create a file like "Download.aspx" that you pass in the file name as a querystring parameter. This way, you can have your server get the file from a location outside of the Web Application's path and adjust the header to force a file download.
Download.aspx
using System.IO;
protected void Page_Load(object sender, EventArgs e)
{
string FileName = Server.UrlDecode(Request.Params["FileName"]); //Example: "MyFile.txt"
Response.AppendHeader("Content-Type", "application/force-download");
Response.AppendHeader("Content-Disposition", "attachment; filename=" + FileName);
Response.WriteFile(#"C:\MyFolder\" + FileName);
}
You would load the page by calling something like "Download.aspx?FileName=MyFile.txt"
You will need to add checks to make sure the file exists and the querystring parameter exists, but that should force the download and allow you to get the file from another location. When you use an ASPX page to serve the file, you can also do credential checks to see if the user is logged into your site (if you have login logic already) or log the download to a log file/database if you want to keep track of it. It gives you a lot more control over the download process.
As for the IFrame loading code, I'm not 100% sure how this works with a file download, but what I was originally thinking was something like this -- view source on: http://sykari.net/stuff/iframe.
Wrap the button in an UpdatePanel, then simply toggle its enabled property before and after the file work.
You can put an IFrame on the page and
set it's visiblity to hidden. Have
your button load the file in the
IFrame and use Javascript to detect if
the IFrame is still loading or not.
When the loading is done, enable your
button.
Can't supply a code example at the
moment, but if you decide to go this
route and need a sample, let me know I
will update this answer.
I've decided to use your suggestion.. but i still have some questions regarding this problem...
Is it possible to load .txt files in iframe?
Is it possible to load some files that are not included in web application's folder?
The problem with loading txt files in iframe is it does not trigger save as dialog to appear, instead of that file content is displayed inside that iframe.
For loading files into an iframe I've used following code:
HiddenFrame.Attributes["src"] = /GeneratedFiles/ + "test.zip";
You can see that I've had to use relative path and my file has to be included in web app's virtual folder.
What is the best javascript (jquery) eventhandler (function) to detect when Iframe has finished loading? I've used jquery function:
$("#ctl00_ContentPlaceHolder1_HiddenFrame").ready(function () {
if ($("#ctl00_ContentPlaceHolder1_HiddenFrame").attr('src') != '') {
$('#ctl00_ContentPlaceHolder1_GenerateSapFilesBTN').removeAttr("disabled");
}
});
But it appears that button is being enabled before Save As dialog actually appears.. Is it possible to solve this problem with this type of eventHandler or do I have to use some other function...
I've created a page that allows users to download a file when they click a button... the button's onclick event is linked to the following chunk of code:
this.Page.Response.Clear();
this.Page.Response.ContentType = System.Net.Mime.MediaTypeNames.Application.Zip;
this.Page.Response.AppendHeader("Content-Disposition", "attachment; filename=\"" + System.IO.Path.GetFileName(filename) + "\"");
this.Page.Response.TransmitFile(filename);
this.Page.Response.Flush();
this.Page.Response.End();
The download works fine, but now when I try to interact with the page, (for instance, hit the download button again), nothing posts back.
Am I responding to the download request incorrectly (should I be using a different/new response object), or is there something else I need to do to make the page active after the download?
Edit:
So I've tried encorporating the two posters suggestions for creating a httphandler, and calling a Response.Redirect to the handler from the button's click event.
void submitButton_Click(object sender, EventArgs e)
{
label.Text = "Boo!";
this.Page.Response.Redirect("~/ViewAttachment.ashx?id=foo", false);
}
If I step through this on the debugger, it continues after the redirect call, but the page just returns to a state where the button doesn't work, and the labels have their default values. Am I now doing the redirect wrong?
If using another handler an option?
Here's a slimmed down version of what I've used before (suggestions welcome this was a quick write). The HttpHandler (AttachmentFile is just a class with the blob data and some attributes collected when the file was uploaded):
public class AttachmentHandler : IHttpHandler
{
public const string QueryKeyID = "ID";
public void ProcessRequest(HttpContext context)
{
var r = context.Response;
var attachmentID = context.Request.QueryString[QueryKeyID];
Attachment a = DataContext.GetById<AttachmentFile>(attachmentID);
r.ContentType = a.ContentType;
r.AppendHeader("Content-Type", a.ContentType);
r.AppendHeader("content-disposition", string.Format("attachment; filename=\"{0}{1}\"", a.AttachmentName, GetExtension(a.FileName)));
r.BufferOutput = false; //Stream the content to the client, no need to cache entire streams in memory...
r.BinaryWrite(a.BlobData);
r.End();
}
private static string GetExtension(string fileName)
{
if(fileName.IsNullOrEmpty()) return string.Empty;
var i = fileName.LastIndexOf(".");
return i > 0 ? fileName.Substring(i) : string.Empty;
}
}
In the web.config:
<system.web>
<httpHandlers>
<add verb="*" path="ViewAttachment.ashx" type="MyNamespace.AttachmentHandler, MyWebDllName"/>
</httpHandlers>
</system.web>
Then all you do is render a link in the form of ~/ViewAttachment.ashx?ID=5 on the page, clicking the button will download the file, but not mess with your page's lifecycle at all.
Now there are more considerations, like security and such....I trimmed them out for this example. I'm also using this style of link: ~/Attachment/{id} via webforms routing...if either of these interest you I'll update to include them. Or you could hate this approach all-together...just letting you know it's an option.
You are mostly there.
All you need to do in your button click event handler is Response.Redirect to another ASPX page. Put that code your wrote on the other page.
Then everything will work just as you expect. The browser will actually stay on the original page and not go to the new page because you have set the content disposition to attachment - which is great.
By using Response.Clear() you've killed the headers. While there may appear to be valid html markup in the browser there really isn't. The headers are gone, so the controls that appear to be still rendered aren't valid. If you click "back" you should be able to repost information. What you probably want to do is make this call in a different window using PostBackUrl in your button click and setting the target of your form to a different window (then using SetTimeout to reset it to _self).