problem in sending document when I click cancel - asp.net

I have a link in aspx page and when i click on it,it shows a popup: open,save,cancel
but when i click cancel on that aspx page no other link works on that page.
code so far:
protected void method1()
{
byte[] byterendered = _Filename.OpenBinary();
Response.Clear();
Response.ClearHeaders();
Response.ClearContent();
Response.ContentType = "image/jpeg";
Response.AddHeader("Content-Disposition", "attachment;filename=abc.jpg");
Response.CacheControl = "Public";
Response.BinaryWrite(byterendered);
Response.End();
}
aspx code
<asp:Linkbutton id="link1" runat="server" onClick="method1" Text="LinkA"/>
<asp:Linkbutton id="link2" runat="server" onClick="method2" Text="LinkB" />

As the comments to your question have indicated, the reason is because your Response is being ended after the file dialog shows up. Once the response ends, any other actions on your page will not be registered. I ran into this myself while implementing a download function for my SharePoint app.
Basically, what you want to do is have your link buttons perform a window open script, instead of directly running the file transfer, like the following.
<asp:LinkButton id="link1" runat="server" onClick="window.open('TARGETURL'); return false;" Text="LinkA" />
Replace TARGETURL with an aspx page URL. Then, create a new ASPX page for the URL you specified. It will be pretty much empty, all you need are two lines.
<%# Assembly Name="YOURFOURPARTASSEMBLYSTRINGHERE" %>
<%# Page Language="C#" Inherits"YOURNAMESPACE.DOWNLOADCODE" %>
Replace YOURFOURPARTASSEMBLYSTRINGHERE with, of course, the four-part assembly string for your code. YOURNAMESPACE.DOWNLOADCODE will be replaced with the namespace and class that you will create for the page. The class will need to inherit the base page type, I personally used LayoutsPageBase since that's a perfect thing to use in a SharePoint app. All this class needs is an OnLoad method like the following.
// Don't actually name your class DOWNLOADCODE.
public class DOWNLOADCODE : LayoutsPageBase
{
protected override void OnLoad(EventArgs e)
{
byte[] byterendered = _Filename.OpenBinary(); //More on this afterwards
Response.Clear();
Response.ClearHeaders();
Response.ClearContent();
Response.ContentType = "image/jpeg";
Response.AddHeader("Content-Disposition", "attachment;filename=abc.jpg");
Response.CacheControl = "Public";
Response.BinaryWrite(byterendered);
Response.End();
}
}
You will have to retrieve _Filename in this new page, of course. The best way to do this is to take whatever parameters you use to determine _Filename in the first place, and pass it as part of the URL query string.
Using this, clicking the link button will open a new window, but since all this page does it have a file response, it will just open the file dialog and be done with it. Meanwhile, your original aspx page will not have ended its response, so it can continue whatever function you need it to.

Related

What is the life cycle of an ASP button?

I'm having an issue with the cycle of a page reload and I can't figure it out. I have an ASP button the runs at the server but it has an associated client side click. The client side Javascript is running correctly and returning true to the button click so it is also running. The Javascript makes a modification to the query string on the URL and this is also working. However, in the C# code behind, the query string is not there. Somewhere, I'm missing something.
The HTML link:
<asp:Button ID="btnRunMOReport" class="button-dbg" runat="server"
Text="Run MO Report" OnClick="btnMO_Report_Click"
OnClientClick="return validateCheckBoxesMO()" />
The JavaScript portion:
function validateCheckBoxesMO() {
token='xyz';
let url1 = window.location.href;
if (url1.indexOf("?") > 0) {
url1 = url1.substring(0, url.indexOf("?"));
}
url1 += "?hiddenToken=" + token;
window.location.replace(url1);
return true;
}
The hiddenToken is now represented on the page (?hiddenToken=xyz).
The code behind:
protected void btnMO_Report_Click(object sender, EventArgs e)
{
MailMessage mailtest = new MailMessage();
mailtest.IsBodyHtml = true;
SmtpClient SmtpServertest = new SmtpClient(ConfigurationManager.AppSettings["smtp_server"]);
mailtest.To.Add("Whoever#test123.com");
mailtest.From = new MailAddress("Whoever#test123.com");
mailtest.Subject = Request.QueryString["hiddenToken"];
mailtest.Body = "Whatever";
}
The mail comes just fine but the subject is blank. Somehow, during the page reload cycle, the query string has not yet been set.
If there is a better way to pass data from the JavaScript to the code behind, I'm all ears.
I want to launch another page from the code behind but I need some data that is returned from the JS. The token is actually something I fetch, process the JSON and now I want to make that token available to the code behind for additional information to add to the new URL I am constructing. Probably TMI for this but it is what I am trying to do.
Thanks for your assistance.
Your script isn't working because the browser makes a POST request to submit the form (and __VIEWSTATE) using the action="" attribute of the <form> that WebForms adds to your page.
When your client-script sets window.location it isn't changing how the <form> will behave. You could use your script to append the new querystring value to the <form>'s action="" attribute and this may work, however it will likely fail if the application has request-validation enabled (in which case ASP.NET will reject a tampered form submission).
As you're using WebForms (and you shouldn't be using WebForms in 2021...) you shouldn't try to fight it unless you understand how it all works (I'm not trying to be condescending: it took me years to figure it all out and I've been using WebForms since 2004).
Instead, provide the value through an <asp:HiddenField>:
Change your .aspx markup to this:
<asp:Button runat="server" ID="btnRunMOReport" class="button-dbg"
Text="Run MO Report" OnClick="btnMO_Report_Click"
OnClientClick="return validateCheckBoxesMO()" />
<asp:HiddenField runat="server" ID="superSecretHiddenField" />
Change your client script to this:
function validateCheckBoxesMO() {
const hiddenFieldId = '<%= this.superSecretHiddenField.ClientID %>';
const hiddenField = document.getElementById( hiddenFieldId );
token='xyz';
hiddenField.value = token;
return true; // <-- This is wrong, btw. Instead use `Event.prototype.stopPropagation()` - but that requires the on-click function to be wired-up correctly and I don't remember the specifics other than that WebForms *doesn't* do things correctly (not out-of-spite, but because WebForms predates the standardisation of client-script events).
}
And your code-behind to this:
protected void btnMO_Report_Click(object sender, EventArgs e)
{
MailMessage mailtest = new MailMessage();
mailtest.IsBodyHtml = true;
SmtpClient SmtpServertest = new SmtpClient(ConfigurationManager.AppSettings["smtp_server"]);
mailtest.To.Add("Whoever#test123.com");
mailtest.From = new MailAddress("Whoever#test123.com");
mailtest.Subject = this.superSecretHiddenField.Value;
mailtest.Body = "Whatever";
}
As noted, a button post back will in general over-write the url that you change. Unless you actually do a navigation client side that is caused by the js, then it will not persist.
So, on the most simple level, just drop in a text box, or hidden field, and put the value you need/want into that hidden textbox or field.
So, client side? Markup?
You can use this:
<asp:Button ID="Button1" runat="server" Text="Delete"
OnClientClick="SetHidden();"/>
<asp:HiddenField ID="HiddenField1" runat="server" ClientIDMode="Static"/>
<br />
<script>
function SetHidden() {
hField = document.getElementById('HiddenField1');
hField.value = 'zoo';
return true;
}
</script>
So in above, we set our value in js to zoo, and of course we do return true. If we return false then the asp.net button code server side will not run - so we can control this, or even say pop up a confirm dialog and return true/false based on that to control if the server side code behind will run.
Server side, code behind? You can now use this:
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Debug.Print(HiddenField1.Value)
End Sub
So the above is easy, clean. You can also use a text box, and set the style="display:none", but a hidden field is just as well and easy.

Changing client side components' properties while server side execution happening in asp.net

I have a <asp:Button /> which is used to export some a DataTable into Excel. I need to display a progress image while the DataTable is being generated. Below is my try for this but still stuck. May be I haven't understand the life cycle here. Appreciate any help.
ASPX
<asp:Button ID="ExportResults" runat="server" UseSubmitBehavior="false" Text="Export Selected" OnClientClick="showWaitingForExport();" OnClick="ExportResults_Click"/>
JavaScript
function showWaitingForExport() {
$("#progressbar").progressbar({ value: false });}
Code Behind
protected void ExportResults_Click(object sender, EventArgs e)
{
DataTable resultDT = GenerateDataTable(); //This is the time taking function and after this I need to hide my progressbar while response still not get end
ScriptManager.RegisterStartupScript(this, this.GetType(), "stopprogress", "$('#progressbar').progressbar('destroy');", true);
string filename = "Search_Results.xlsx";
workbook.AddWorksheet(resultDT, "Search Results");
workbook.SaveAs(Server.MapPath("~/Temp/" + filename));
Response.ContentType = "application/vnd.ms-excel";
Response.AppendHeader("Content-Disposition", "attachment; filename=" + filename + "");
Response.TransmitFile(Server.MapPath("~/Temp/" + filename));
Response.End();
}
Unless I misunderstood the question, check out this link - it's a fairly common thing that developers need to do: http://www.dotnetcurry.com/showarticle.aspx?ID=227
OnClientClick is called when you click the button, but then the request goes to the server (OnClick="ExportResults_Click") and the browser/client will show the normal loading page (usually a blank white page). You should be able to use an UpdatePanel with one of the strategies described in the link to show an update panel progress bar. The only way around this (that I'm aware of) is to use an async postback so the page is still displayed while the server is processing.
Does this make sense? Does the article help? I can go into more detail or show an example if necessary. I am not at a computer with Visual Studio to throw together an example, but I can post something tomorrow if no one else has answered.

Writing to the browser repeats when clicking another button on the page

I have a page that has a button:
<button id="btnExport1" runat="server" class="btn btn-success" style="width: 120px;" OnServerClick="btnExport_Click">Export</button>
The btnExport_Click method prepares an Excel file which is then sent to browser using the following code
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.ClearContent();
var attachment = String.Format("attachment; filename=\"SR_ChargeExport_{0:yyyy-MM-dd_HH-mm-ss}.xlsx\"", DateExtensions.CurrentDisplayTime());
HttpContext.Current.Response.AddHeader("content-disposition", attachment);
HttpContext.Current.Response.ContentType = "application/vnd.ms-excel";
HttpContext.Current.Response.WriteFile(filename);
HttpContext.Current.Response.Flush();
if (deleteFile)
File.Delete(filename);
HttpContext.Current.Response.End();
There is also a LinkButton on the page which when clicked runs some javascript on the page to open up a Telerik RadWindow and passes in the url of a new page. On this page there is a LinkButton that looks like this:
<asp:LinkButton ID="btnUpdate" CssClass="btn btn-success" runat="server" OnClick="btnUpdate_Click"><span>Add Comment</span></asp:LinkButton>
And in btnUpdate_Click there's some code that basically saves a comment and closes the RadWindow.
The problem I'm having is that after you click the Export button to download a file, if you then add a comment by clicking the button in the RadWindow another Excel file is downloaded. The AddComment code does get run but then the Export code gets run again straight after. I'm thinking it's something to do with not being able to post back to the page after writing to the browser in the Export code.
Make the request for your Excel download be asynchronous via an HTTP Handler, thus you can do this instead:
Markup:
<a href="#" class="btn btn-success"
src="PATH_TO_YOUR\HTTP_HANDLER.ashx">Export</a>
ExportToExcelHandler.ashx:
public class ExportToExcelHandler : IHttpHandler {
public void ProcessRequest (HttpContext context)
{
context.Response.AddHeader("content-disposition","attachment; filename=excelData.xls");
context.Response.ContentType = "application/ms-excel";
// Put logic here to create Excel download
// Stream it back to browser
}
public bool IsReusable
{
get
{
return false;
}
}
}
After further investigation I found out that there was javascript being run for the OnClientClose event of the RadWindow. In there it was submitting the form (in order to update the comments on the page) so I changed it to do a 'location.reload()' instead.

Is response to Ajax call different from that of to full postback

When I try the following code with a postback the file download takes place normally:
FileInfo file = new FileInfo("C:\\a.txt");
Response.ClearContent();
Response.AddHeader("Content-Disposition", "attachment; filename=" + file.Name);
Response.AddHeader("Content-Length", file.Length.ToString());
Response.ContentType = "text/plain";
Response.TransmitFile(file.FullName);
Response.End();
However if I put the above code inside a public static web method and call it with AJAX I get error, like "Process was being aborted".(Of course to get the current response I write HttpContext.Current.Response) This makes me think that the nature of the two responses are different. My question is if they are different, then what exactly is/are different? Is there a way to achieve the same thing with AJAX?
The browser isn't going to receive the file via an XHR (Ajax) call. You will want to return the file location and then send the browser to that file via window.location or window.open.
Edit: Here's a Web Forms sample. My Web Forms skills are a little rusty since I've been using MVC now; the syntax is off the top of my head so you might need to fix it up a little.
ASPX Page
<div id="whateverIsContainingYourDialog">
<form id="mikeJMIsAwesome" runat="server">
<asp:TextBox id="firstName" runat="server" />
<asp:TextBox id="lastName" runat="server" />
<asp:Button id="submit" runat="server" />
</form>
</div>
Server Side Code
protected void submit_OnClick(object sender, EventArgs e) {
//Your logic for creating the file and the code you originally posted for serving the file.
}
What Ek0nomik said, file downloads are handled by the browser and cannot be handled through Javascript. The responses are both identical they are are both just http responses - you can verify this with fiddler or another tool (http://www.fiddler2.com/fiddler2/).
Essentially you ajax method will not be able to handle receiving a file and will certainly not have the permissions to assemble it and store it on you hard drive.
You can 'fake' a user clicking on a link using some Javascript.
Please check this similar question for an answer. I've pasted the answer from it below.
starting file download with JavaScript
We do it that way: First add this script.
<script type="text/javascript">
function populateIframe(id,path)
{
var ifrm = document.getElementById(id);
ifrm.src = "download.php?path="+path;
}
</script>
Place this where you want the download button(here we use just a link):
<iframe id="frame1" style="display:none"></iframe>
download
The file 'download.php' (needs to be put on your server) simply contains:
<?php
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=".$_GET['path']);
readfile($_GET['path']);
?>
So when you click the link, the hidden iframe then gets/opens the sourcefile 'download.php'. With the path as get parameter. We think this is the best solution!

Downloadinf a pdf in new window without redirecting

I have an aspx page which has several controls. When I click a button on this page,
I need to get the values of the textbox and dropdowns and do some processing and pass it on to another aspx page. The second aspx will do further processing and generate a pdf to download.
I don't want the user to be redirected to the second page. I simply want the pdf download to appear in a new window.
How can I achieve this?
You need to set the Content-Disposition http header and return the pdf directly.
Like this:
Response.ContentType = "application/x-download";
Response.AddHeader("Content-Disposition", string.Format("attachment; filename=\"{0}\"", fileName));
Response.WriteFile(filePath + fileName);
Response.Flush();
Response.End();
Note: Don't set the Content-Disposition to application/pdf as this is recognized by many browsers and they will try to open it with the pdf-reader embedded in the browser.
How to post to second page on button click?
Set the PostbackUrl on your button click like this:
<asp:Button
ID="Button1"
PostBackUrl="~/TargetPage.aspx"
runat="server"
Text="Submit" />
You can read values from your current page on target page by accessing the controls using the PreviousPage property as follows:
TextBox SourceTextBox =
(TextBox)Page.PreviousPage.FindControl("TextBox1");
if (SourceTextBox != null)
{
Label1.Text = SourceTextBox.Text;
}

Resources