Run JavaScript after an "Attachment Response" in ASP? - asp.net

So here is my problem: I have a code that use response to ExportFile, but the problem is after the response code. the succeeding code no longer executes or it is like being read but ignored. sorry for being noob. so here is my code:
fullFilePath = "" + rootPath + "" + Filename + ".xlsx";
string fileName = fullFilePath.Substring(fullFilePath.LastIndexOf('\\') + 1);
byte[] buffer;
using (FileStream fileStream = new FileStream(fullFilePath, FileMode.Open))
{
int fileSize = (int)fileStream.Length;
buffer = new byte[fileSize];
// Read file into buffer
fileStream.Read(buffer, 0, (int)fileSize);
}
Response.Clear();
Response.Buffer = true;
Response.BufferOutput = true;
Response.ContentType = "application/x-download";
Response.AddHeader("Content-Disposition", "attachment; filename=" + fileName);
Response.CacheControl = "public";
// writes buffer to OutputStream
Response.OutputStream.Write(buffer, 0, buffer.Length);
newFile.Delete();
ClientScript.RegisterStartupScript(GetType(), "id", "EnableCtrl()", true);
after this has been executed the javascript "EnableCtrl()" is not being fired or triggered. And when I delete the part of code which is related to response and change it to something else the javascript is being triggered. So how could i run a javascript after a response code?

The script won't/can't be triggered this method because the browser has already been sent the response: which is the file, and not the markup from a post-back. One request. One response. And it wasn't the post-back markup.
Instead, I would suggest either:
Handling the "Client Click" of the initiating control in the browser as well (the action could be delayed with setTimeout). Browser won't actually refresh the page/DOM because of the attachment disposition in the response, which is why this works. However, there are no client-side events for if a download was accepted, has started, or has completed1
Change the design so the "download" is a separate action with no other side-effect.
Happy coding.
1 It's possible to contrive server-assisted setups that allow the client to query the progress of a download, much like an upload progress indicator. However, this is not trivial or standard and may still not accurately reflect the state.

Related

ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION - unable to find out why

I'm getting ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION when returning my docx file, however I'm not sure where in my header the error comes from. I've tried my best to remove anything that is dynamic and hardcoded to figure it out, to no avail.
byte[] byteArray = File.ReadAllBytes(#"T:\Praktik log\Learning Goals.docx");
using (MemoryStream mem = new MemoryStream())
{
mem.Write(byteArray,0,byteArray.Length);
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(mem, true))
{
RevisionAccepter.AcceptRevisions(wordDoc);
wordDoc.MainDocumentPart.Document.Body.InsertAt(
new Paragraph(
new Run(
new Text("Newly inserted paragraph."))), 0);
}
Response.Clear();
Response.ClearContent();
Response.ClearHeaders();
Response.Cookies.Clear();
//Add the header & other information
Response.Cache.SetCacheability(HttpCacheability.Private);
Response.CacheControl = "private";
Response.Charset = System.Text.UTF8Encoding.UTF8.WebName;
Response.ContentEncoding = System.Text.UTF8Encoding.UTF8;
Response.AppendHeader("Content-Length", mem.ToArray().Length.ToString());
Response.AppendHeader("Pragma", "cache");
Response.AppendHeader("Expires", "60");
Response.AppendHeader("Content-Disposition",
"attachment; " +
"filename=\"ActivationKey.docx\"; " +
"size=" + mem.ToArray().Length + "; " +
"creation-date=" + DateTime.Now.ToString("R") + "; " +
"modification-date=" + DateTime.Now.ToString("R") + "; " +
"read-date=" + DateTime.Now.ToString("R"));
Response.ContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
//Write it back to the client
Response.BinaryWrite(mem.ToArray());
Response.End();
I can download it on IE as it's gives crap about security, but chrome says nogo, and I need to have Chrome support for this download.
EDIT: Fiddler response: https://prnt.sc/pddibg
You're doing one weird thing.
Response.Clear();
Response.ClearContent();
Response.ClearHeaders();
Response.Cookies.Clear();
ASP.NET places some headers itself.
Please try to not remove them and use native (if they exist for headers you're trying to modify, of course) ASP.NET methods to modify response headers.
Also you can setup a HTTP debugging proxy.
It will help you see what exactly you are doing wrong.
Here's some HTTP debugging proxies I know: Fiddler, Wireshark or Charles (paid, requires Java).
This guy achieved file downloading via returning System.IO.File.
Also this question looks like yours.
Check these answers, they may help you.
I achieved downloading a named file via:
[HttpGet]
public void Get()
{
Response.Headers.Add("Content-Disposition", "attachment; filename=\"file.bin\"");
var buffer = Enumerable.Repeat((byte) 0xF, 2048).ToArray(); //bytes
Response.Body.Write(buffer, 0, buffer.Length);
}
Tested on Google Chrome (Version 77.0.3865.90).
File downloaded and contains 2048 bytes of data.
Server response in Fiddler: screenshot

download code expalanation in asp.net

can anyone please explain this code
if (e.CommandName == "download")
{
string filename = e.CommandArgument.ToString();
string path = MapPath("~/Docfiles/" + filename);
byte[] bts = System.IO.File.ReadAllBytes(path);
Response.Clear();
Response.ClearHeaders();
Response.AddHeader("Content-Type", "Application/octet-stream");
Response.AddHeader("Content-Length", bts.Length.ToString());
Response.AddHeader("Content-Disposition", "attachment; filename=" + filename);
Response.BinaryWrite(bts);
Response.Flush();
Response.End();
}
what is command argument, mappath, and also what is this
"Content-Type", "Application/octet-stream"
and also
Response.AddHeader("Content-Length", bts.Length.ToString());
Response.AddHeader("Content-Disposition", "attachment; filename=" + filename);
Response.BinaryWrite(bts);
Response.Flush();
First, I advise you to use the MSDN documentation to search for more information about the objects and methods you wanna know more about. MSDN is a useful network and should be used.
Quoting the MSDN CommandArgument : "Gets or sets an optional parameter passed to the Command event along with the associated CommandName". It is used to get an parameter that was passed to the command event. In this case, it was the file name.
string filename = e.CommandArgument.ToString();
The MapPath is used to map a specified path to a physical path. Using this you get the real path of the file. For example: "C:\Docfiles\Yourfile.pdf"
string path = MapPath("~/Docfiles/" + filename);
The ReadAllBytes method, opens a file, reads the content and then closes the file. This return the content of this file as a byte array.
byte[] bts = System.IO.File.ReadAllBytes(path);
The Response object is used to send output to the user from the server.
Response.Clear();
Response.ClearHeaders();
Response.AddHeader is used to build the header of response that will be sent back to user. We use it to set infos about the data we are sending back to the client.
The "Content-Type" attribute is used to especify what kind of file you are returning to the user.
Response.AddHeader("Content-Type", "Application/octet-stream");
The "Content-Length" attribute is used to inform to the browser the size of the the file you are returning.
Response.AddHeader("Content-Length", bts.Length.ToString());
The "Content-Disposition" is used to inform the name of the file that will be returned. For example "file1.doc"
Response.AddHeader("Content-Disposition", "attachment; filename=" + filename);
The "BinaryWrite()" write your file (who, at this moment, is in a byte array format) to the current HTTP output without any character conversion.
Response.BinaryWrite(bts);
The Flush method sends buffered output immediately.
Response.Flush();
And, finally, causes the server to stop processing the request and return the current result.
Response.End();
If the command is download, most likely from a grid button, then get the name of the file as the argument (these are properties on a button control), and send it to the browser. This prompts the user to download the file.

TransmitFile continue with page_load efter Response.End

I've been looking for an answer for a week now and I give up.
I'm creating an excelfile and then let the user download it to his client with TransmitFile.
The thing is, this works perfectly most of the time, but in some cases (can be repeated), after the Response.End, the page reloads and page_load is called. The flag IsPostBack is false.
This behaviour interrupt the download and the whole application stop working, displaying connecting to server.
foreach (string filename in Directory.GetFiles(WebConfigurationManager.AppSettings.Get("EXCEL_PATH")))
{
if (File.GetLastWriteTime(filename) < (DateTime.Now.AddDays(-1)))
{
File.Delete(filename);
}
}
ClsOrderFormData ofData = new ClsOrderFormData(ddOrderTypes.SelectedValue, OF.Customer.CustomerCategory);
ClsExportOF xls = new ClsExportOF(OF.SizeDims, ofData, OF.Customer, Request.PhysicalApplicationPath, ClsPrintOrder.getOrderData().TheOrder.Articles);
string sFileName = xls.CreateExcelFile();
FileInfo OutFile = new FileInfo(WebConfigurationManager.AppSettings.Get("EXCEL_PATH") + sFileName);
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=Abacus_OF_" + ddOrderTypes.SelectedItem.Text + "_" + ddCustomer.SelectedItem.Text + "_" + DateTime.Now.ToShortDateString() + ".xls".Replace(',', '-'));
Response.ContentType = "application/vnd.ms-excel";
Response.TransmitFile(WebConfigurationManager.AppSettings.Get("EXCEL_PATH") + sFileName, 0, OutFile.Length);
Response.Flush();
Response.End();
In short. When it works no more code is executed after Response.End(), as expected. When it don't work it continue with page_load and so on, and the site hangs.
Any tips?
Trying using HttpApplication.CompleteRequest instead of Response.End. Response.End is probably throwing a ThreadAbortException which is messing up the process.
see...
http://ardalis.com/Use-HttpApplication.CompleteRequest-Instead-of-Response.End
http://weblogs.asp.net/hajan/archive/2010/09/26/why-not-to-use-httpresponse-close-and-httpresponse-end.aspx

Present a PDF Document on a Specific Page in ASP.NET

I am opening PDF documents using the following ASP.NET code,
Response.BufferOutput = true;
Response.Clear();
Response.ContentType = "application/pdf";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(documentURL);
using (HttpWebResponse responseDDRINT = (HttpWebResponse)request.GetResponse())
{
using (Stream stream = responseDDRINT.GetResponseStream())
{
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int bytesRead;
while ((bytesRead = stream.Read(buffer, 0, bufferSize)) > 0)
{
Response.OutputStream.Write(buffer, 0, bytesRead);
}
Response.Flush();
}
}
My question is does anyone know how to present the PDF starting at a specifice page. For example, if the PDF document is 15 pages, we would like it to open with page 10 initially showing instead of opening at page 1.
I experimented with the "#page=" open parameter by adding this header, but it did nothing.
Response.AddHeader("content-disposition", "inline; filename=test.pdf#page=3");
You'll have to manipulate the PDF file on the fly.
Use something like http://pdfsharp.com/PDFsharp/ to stream out a copy of the file starting at a certain page.
Current versions of Adobe ready no longer support the page syntax, but they do support the bookmark syntax.
Why don't you make your document reachable through a regular link or through an HTTPHandler?
you may use a PDF manipulation library like ItextSharp to get your work done.

Using JQuery to retrieve a physical file and then display it in the browser

UPDATE:
Most of the answers given have just been some way of injecting the returned document into the html of the page, but this does not seem to be working. It might help if you could see what the aspx code is doing after all:
Try
RenderDocument = Session("docSelected")
If Not String.IsNullOrEmpty(Request.QueryString("download")) Then
asDownload = CBool(Request.QueryString("download"))
End If
If RenderDocument IsNot Nothing Then
Dim docBytes() As Byte
Dim docExtension As String = ""
Dim docFileSize As Long
GetBytesAndExtension(docBytes, docExtension, docFileSize)
If docBytes IsNot Nothing Then
Dim ms As New MemoryStream(docBytes)
With ms
Dim dataLengthToRead As Long = ms.Length
Dim blocksize As Integer
If dataLengthToRead >= 5000 Then
blocksize = 5000
Else
blocksize = dataLengthToRead
End If
Dim buffer(dataLengthToRead) As Byte
Response.Clear()
Response.ClearContent()
Response.ClearHeaders()
Response.BufferOutput = True
If asDownload = True Then
Response.AddHeader("Content-Disposition", "attachment; filename=" & RenderDocument.Name & "." & docExtension)
Else
Response.AddHeader("Content-Disposition", "inline; filename=" & RenderDocument.Name & "." & docExtension)
End If
Response.AddHeader("Content-Length", docFileSize.ToString())
Response.ContentType = "application/octet-stream"
While dataLengthToRead > 0 And Response.IsClientConnected
Dim lengthRead As Integer = ms.Read(buffer, 0, blocksize)
Response.OutputStream.Write(buffer, 0, lengthRead)
dataLengthToRead = dataLengthToRead - lengthRead
End While
Response.Flush()
Response.Close()
End With
Response.End()
Else
ResponseWithMessage("No Data")
End If
Else
ResponseWithMessage("No Document")
End If
Catch ex As Exception
ResponseWithMessage("ERROR: " & ex.Message)
End Try
What is the significance of the return type of the $.post() function? In my code I use 'html', but actually it could be a file being returned.
===================
ORIGINAL QUESTION:
The scenario is I want to load a html page which will call a specific ASP.Net script, this script returns a document based on some data stored in the session. It's function is irrelevant, essentailly it returns the document as an http response, however it may return one of several error strings depending on what has occured.
The html page shows a loading gif image and then when the document or error message is returned it needs to handle these appropriately.
I can get the page to display the error messages without a problem, but I don't know how best to handle the document request being returned, at the moment it just opens a new window and calls the url again, but that is clunky and calls the whole document retrieval process again (synchronously!) which defeats the purpose of using a nice ajax style load.
This is my JQuery code:
$(document).ready(function(){
$.post("displaydocument.aspx",null,function(data){
if (data == 'No Document'){
UpdateControls('No document has been specified to load');
}
if (data == 'No Data'){
UpdateControls('No data was found for that document');
}
if (data.indexOf('ERROR',0) != -1) {
UpdateControls(data);
}
window.open("displaydocument.aspx","doc");
window.close;
}
, "html");
});
function UpdateControls(message){
$("#txtInfo").html(message);
$("#imgLoading").hide();
}
This is my html:
<div style="text-align: center; font-family: 'Trebuchet MS';">
<img alt="loading" src="/images/loader64.gif" id="imgLoading" />
<br />
<span style="font-size: small" id="txtInfo">Document is loading...</span>
</div>
Your assistance is as always highly valued.
Thanks
Updated: I think the problem is that you are trying to do too much in one method. I would split it into two operations: check that the document is available and download the document. Have the method you call via POST (GET would work too since you aren't passing any data) do the existence check then create a link to a document handler URL that does the actual download. Add the link to the page and programmatically click it to invoke the download handler. The download handler would consist of your existing code and simply return an error page if invoked on a non-existent document. Note that the latter will not happen in normal operation, but could if someone bookmarked the downloaded document and it was removed.
Also, I'd be tempted to use JSON for the return value instead of HTML to make handling the error easier.
$(function() {
$.get('checkfordocument.aspx',null,function(data) {
if (!data.Success) {
UpdateControls(data.Message);
}
else {
UpdateControls('');
$("<a href='"
+ data.Url
+ "' target='_blank' class='docLink'>"
+ "Click here if your document does not start downloading</a>")
.appendTo('#txtInfo')
.trigger('click');
}
,'json');
});
Open your window and set it's contents using JS instead of sending another request to the server.
Instead of
window.open("displaydocument.aspx","doc");
do something like:
var win = window.open();
win.document.write(data);
This will set the contents of the new window without retrieving the data again.
I would create a web/wcf service who's responsibility is to notify you if a certain file exists. You could then return a simple json string with either a success flag and if it fails a relevent error message.
This also saves the need to request the file twice and you would also gain a reusable service for future pages & projects. I know the response for the document should be cached however the above functionality allows you to give greater error message notification to the user.
$.getJson('fileExistsService.svc', { filename : someName }, function(data){
if (data.success){
//open document
window.open("displaydocument.aspx","doc");
}
else {
//display error to use
//alert(data.errorMessage)
}
})

Resources