JQuery BlockUI - How to unblock UI after file download? - asp.net

Using ASP.Net, JQuery and BlockUI, I'm trying to unblock the UI after a download file dialog is shown.
I block the UI when export button is clicked:
<script type="text/javascript">
$(document).ready(function(){
$('#<%= BtnExport.ClientID%>').click(function(){
$.blockUI();
});
});
</script>
After this, I generate the file server side using:
private void SendFileToUser(byte[] file, string contentType, string filename)
{
Response.Clear();
Response.ContentType = contentType;
Response.AppendHeader("Content-Disposition", "attachment; filename="+filename);
Response.OutputStream.Write(file,0,file.Length);
Response.OutputStream.Flush();
Response.End();
}
After this code has executed, I would like to unblock the UI.
I have considered different options:
Poll using Ajax calls to see if the file has been generated.
Store the file in Session and redirect to same page and generate download then.
But both options seem ackward, and I think there must be a clever JavaScript way to get a handle on or wait for a file dialog.
Any suggestions?

There is no way to check this; there is no event like ondownloadready.
But there are some work-arounds
http://gruffcode.com/2010/10/28/detecting-the-file-download-dialog-in-the-browser

Don't store the file in the session, that's a huge waste of resources. Why not just post your form data to a "download" page with a "Your file should download momentarily..." message. This is how popular download sites like www.download.com do it when arrive at their download page.
This gives the user the opportunity to retry simply by refreshing, and you don't need to worry about session timeouts because all your data is in the POST header when they arrived at the page.

The method I used is to send a cookie in addition to the file attachment which you can detect via a timeout using JavaScript and then unblock the ui
Details are here http://geekswithblogs.net/GruffCode/archive/2010/10/28/detecting-the-file-download-dialog-in-the-browser.aspx

Related

Winform browser control "attachment" button

We have a winform app that has a browser control on it. Previously these files (always very small 10kb etc.) were stored at a unc location. We would generate some html and load the html into the browser. If we wanted to make one of these small files available we would include in the HTML an anchor tag () WHen the html was displayed in the browser control so would be the link. The user could click on the link and the file save as dialog would appear.
We are now storing these files in the db as varbinary and thus there is no longer a physical location for the anchor tag to point to. I have several thoughts but would like the members of SO who are way smarter than me to chime in.
Option 1 in my mind would be to have an image button, anchor tag, something in the html to click on. I would handle the "onclick" either in javascript or as a postback. This seems doable for my level of knowledge EXCEPT I do not know how to get the byte[] to translate into the save as dialog for the user....do I render it to disk first?
The other idea I had was to have a button that is NOT in the browser control. This button would be hidden / visible if the biz rules said to show a file. Clicking on the button would then generate the byte[] which is easily turned into a file and the save as shown dialog shown in the winform app.
So any thought or all together different suggestions welcome
TIA
JB
I understand that you are in control of the ASP.NET web page shown in the windows forms web browser control so you can edit that page and build it the way you want.
if that is true, behavior in hosted web browser or in normal IE session is the same and I would suggest to create a bunch of hyper links or buttons in the asp.net web form page each one which a specific ID, like the ID of the file to download. then you can create an handler or a button_click event handler where you get the byte[] of the file by the clicked button/link associated file Id, or from query string if you initiated an handler call, and then you start streaming down to the browser the file content, the browser will do all what is required for you.
for example, just as a starting point, a bit of code taken from here: http://social.msdn.microsoft.com/Forums/en-US/silverlightnet/thread/d6a5087f-43b1-4782-95f1-d1376130d2c8
shows you a possible way to do this from a page load, the trick is that the call to GetDocument gets the proper file content for you (in this case from the query string, imagine like if we are inside an handler processing method) and returns a class DocumentInfo which contains the bytes. you do nor need this DocumentInfo, you can just have a method which returns byte[] by File Id for example...
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
string queryString = this.Request.QueryString.ToString();
if (string.IsNullOrEmpty(queryString)) return;
DocumentInfo documentInfo = GetDocument(queryString);
if (!documentInfo.HasValue) return;
Response.ClearHeaders();
Response.ClearContent();
Response.AppendHeader("Content-Length", documentInfo.Value.Content.Length.ToString());
Response.ContentType = "application/octet-stream";
Response.AppendHeader("Content-Disposition", "attachment; filename=Test.doc");
Response.BinaryWrite(documentInfo.Value.Content);
Response.End();
}
}

ASP.NET button that performs a server-side action, returns a file to download, and plays nicely with an UpdateProgress... In a single request

I have an ASP.NET page (using ASP.NET AJAX and the Telerik RAD components) that provides a data table and an option to download data in CSV format.
I have a requirement that a single button allow the user to download a data set. I have a system set up that's nearly working for me based off the solution in
Response.Redirect to new window
My ASPX looks like this:
<asp:Button ID="ExportCsvButton" runat="server" Text="Download to CSV/Excel"
OnClick="ExportCsvButton_Clicked" OnClientClick="aspnetForm.target = '_blank';" />
Then in my codebehind for ExportCsvButton_Clicked, I do something like this:
byte[] csvBytes = someLongOperation();
Session[EXPORTED_SESSION_KEY] = csvBytes;
Response.Redirect("myexportpage.aspx", true);
Finally, in my 'myexportpage' codebehind, I'm doing this:
protected void Page_Load(object sender, EventArgs e)
{
Response.Clear();
Response.ClearHeaders();
Response.ClearContent();
Response.AppendHeader("content-disposition", "attachment; filename=" + "file.csv");
Response.ContentType = "text/csv";
Response.AddHeader("Pragma", "public");
Response.BinaryWrite(Session[OtherPage.EXPORTED_SESSION_KEY] as byte[]);
Response.Flush();
Response.End();
}
This actually works quite well. When I click the 'Export to CSV' button, the page's UpdateProgress kicks in and my loading overlay appears (it's a CSS div that covers the window when visible). This can take some time depending on the data set (potentially several minutes), at which point I'm getting a window popup with my file. I can save or open the file in my browser and when I save the file I can continue on the page with my export button. Cool.
My only problem is that the UpdateProgress never goes away - the postback isn't completing (because I'm redirecting the response to the mini export page and there's no dedicated response to the postback request?).
I can use a very brittle solution, if need be, as this functionality is unlikely to be needed anywhere else in the web app for the remainder of its life.
I'm very green at AJAX so wouldn't be surprised if there isn't already an elegant solution I can use. What I really want to avoid is forcing the user to initiate a second request to initiate the download (like you see on file download sites = "your download won't begin in the next 5 seconds, so just click here").
Any thoughts?
I don't think this is possible - the file download and the result to the UpdateProgress need two separate responses.
My solution required 2 clicks but no page transitions.
My Export button fired off the action to generate the exported data, which I serialized in the user's session. When this action completed, I hid the export button and made a 'Your download it ready. Click here to save' link visible in its place on my page. That all happened at the end of the event handler for the export button.
When the user clicked the download link, the event handler for that sent the export data to the user.
I opted to leave the download link visible after that until the user refreshed the page or changed some other controls on the page that would change what data was exportable.

Unblock (jQuery BlockUI) after file sent to browser through response stream

I have an <asp:button /> that generates a PDF report. I want to use jQuery BlockUI to display a message that says: Generating Report..
Using: Response.BinaryWrite I am then sending the file to the user so it appears as a file download in the browser.
I cannot get $.unblockUI(); to fire. As soon as the file download begins or has completed or is cancelled I want it to dissappear. Currently it never does.. It's as though the page hasn't been re-loaded, I've hit the server but it comes back with the same page.
Things I have tried:
Setting a variable in JS to true so on document.ready() it will call a function if set to true. This doesn't work because even though I change the variable in code it doesn't change the HTML that is sent to the client.
This sort of thing: Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(function() { $.unblockUI; }); //register with Microsoft way
$(document).ajaxStop($.unblockUI); //double the insurance and register with jquery way
never gets called..
Can this be achieved with an updatepanel?
Any thoughts?
Also in case it helps:
Response.AddHeader("Content-Disposition", "attachment;filename=""" & ShortFilename & """")
Response.AddHeader("Content-Length", byteArray.Length)
Response.BinaryWrite(byteArray)
Response.Flush()
Response.End()
I can see why this doesn't work sort of, the page is not refreshing in anyway there's just a response stream being sent to the browser, but surely there's an event I can latch on to?
An idea could be to create a child window that does the PDF loading and let the parent figure out when the child window has closed or something.
Is it possible for parent window to notice if child window has been closed?
The solution is to first block the UI as normal. Then make an AJAX request to your report generator, when the PDF is generated store it locally for a short time, or have it in a temporary folder that is cleared out when the user logs out or their login times out. Have the report generator return a success message and a URL.
Have the client ajax request handle the success message, remove BlockUI, then call the URL using:
window.location="http://yourURL/temp/report.pdf
The browser will start to download the file and you are done!
https://stackoverflow.com/a/7660817/181197

ASP.Net HyperLink and Download directly?

want to have a Hyperlink-Button in a gridView in which I can display a Link for a direct download of files.
So far I am okay, but when I link the file in the NavigateURL, I don't get the file via click, I must right click -> Save as!
That I don't want. Any help?
You could set up an ashx file handler. Your ashx takes the request through the querystring, loads the proper file into memory, sets the proper response headers and streams the file to the browser:
FileInfo fileInfo = new FileInfo(PATH-TO-YOUR-FILE); //You need to specify this
context.Response.ContentType = YOUR-CONTENT-TYPE; //And this
context.Response.AddHeader("Content-Length", fileInfo.Length.ToString());
context.Response.WriteFile(fileInfo.FullName);
context.Response.Flush();
context.ApplicationInstance.CompleteRequest()
This lets you have some fine-grain control over the content that is being delivered if you have any concerns about security or maybe keeping track of who has downloaded what file, etc.
This sounds like a browser issue. Possibly the browser is trying to open up some application to handle this and failing. Double-check your application associations and/or try a new browser.
I would add also "Content-Disposition" header to response:
context.Response.AppendHeader("Content-Disposition", "attachment; filename = " + filename);

Showing page load progress with JavaScript

I am retrieving a list of files from a web service and displaying them as links. When someone clicks on the link, the file should start downloading. The problem is that no direct access to the file exists. Here is the process to download a file:
User clicks on link
Server calls web service to retrieve file
Browser is loading for as long as it takes to bring the file back from the web service
Browser finally offers file to user for download
To counter the unfavorable user experience of having to wait for the web service before the download starts, I would like to display a "Loading..." feedback dialog when a link is clicked, and have the dialog go away when the file is ready.
I am using jQuery, and have been playing around with adding an iframe to the page to load the file, but the problem I am having is I don't know how to determine that the file is ready.
I am looking for tips, not only on the client side to give ample feedback, but perhaps also on the server side (using ASP.Net), just in case I can do something to streamline the process. Thank you.
Update: To clarify, this is for downloading a file to a user's machine. What I'm specifically looking for is a way to determine when the file is ready for download. So, when step #4 above takes place, I'd like to remove the "Loading..." message.
It sounds like you need to expose a new request URL on your server, whose only job is to reply whether the web-service-retrieval has completed (or if not, how far it has got).
Have AJAX poll that service every few seconds, and remove the "Loading..." message when it replied that the file is ready.
The client should send the session ID (maybe also a file ID), so that the server knows which file is being asked about. The server side will need to be able to contact the running web-service-retrieval process/thread to ask it how far it got. (If it can't find the thread then presumably it has finished.)
you can use the complete option for $.ajax function in jquery which should get called when the request completes
You can have jQuery to wait for the click of the link and when the link is clicked show the display loading message.
Example that shows how to 'Loading - Please wait' Message Display Script you can follow.
EDIT-
Basically you want a progress bar monitor, which I have never seen it done with just javascript, but with flash or ajax.
Here is a File Upload Demo that should help.
If you're linking to an ASHX that is grabbing the file and writing it back to a stream, you can modify the links click event to display a message.
$(function () {
$("a.someClass").click(function () {
$("div.message").fadeIn(); // show a loading message
return true; // make sure the link still gets followed
});
});
The loading message can just be a spinner or something while waiting for the ASHX to write the response back.
Edit: Since you're not directly linking to the ASHX:
$(function () {
var ashxCallback = function (data, textStatus) {
// data could be: xmlDoc, jsonObj, html, text, etc...
this; // the options for this ajax request
// textStatus can be one of: "timeout", "error", "notmodified", "success", "parsererror"
alert(textStatus);
};
$("a.someClass").click(function () {
$("div.message").fadeIn(); // show a loading message
$.get("some.ashx?id=1234", "", ashxCallback);
return false;
});
});
Using jQuery.get() and jQuery.post().
Edit #2: I just had another thought. What if the Loading... message was in an iframe that redirected to the file? So you would display the iframe with jQuery, it would have the default message of Loading... and a little spinner animation, then set the iframe's src/location to the ASHX that takes forever to load. You could then give it an onload handler from the iframe's parent page that would hide/remove it. Let me know if you need sample code.
If preparation for the file takes less than default timeout of AJAX request, you may start AJAX request, displaying "Loading..." message to user. AJAX call then checks for file's availability, and when it becomes available - returns with the message (success or not) and gives a link for the file. AJAX request can even do file download, but that's for your option.

Resources