ASP.NET Response.End Problem - c#

i got a page users downloading files from there.And when a user click download link and finish downloading file , i am insertin' a new record for my File Download Counter event. (FileID,Date,blalbla..)
But there is problem with my script ... after download starts and finish, its adding a new record but after this, its fires event again and making a new record too.So 1 download and 2 new download record. here is my script;
if (Page.Request.QueryString["FileID"] != null)
{
OleDbCommand command = new OleDbCommand("select * from Dosyalar where DosyaID=" + Page.Request.QueryString["FileID"].ToString(), veri.baglan());
string dosyaAdi = "";
int DosyaID = 0;
OleDbDataReader dr = command.ExecuteReader();
while (dr.Read())
{
dosyaAdi = Server.MapPath("formlar") + "\\" + dr["URL"].ToString();
DosyaID = Convert.ToInt32(dr["FileID"]);
}
dr.Close();
FileInfo dosya = new FileInfo(dosyaAdi);
Response.Clear();
Response.AddHeader("Content-Disposition", "attachment; filename=" + dosya.Name);
Response.AddHeader("Content-Length", dosya.Length.ToString());
Response.ContentType = "application/octet-stream";
Response.WriteFile(dosyaAdi);
// INSERT A NEW RECORD
OleDbCommand ekle = new OleDbCommand("Insert into Indirilenler (FileID,Tarih) values (#p1,#p2)", veri.baglan());
ekle.Parameters.AddWithValue("p1", FileID);
ekle.Parameters.AddWithValue("p2", DateTime.Now.ToShortDateString());
ekle.ExecuteNonQuery();
Response.Flush();
Response.End();

The problem is that the browser is actually making two requests to get the file. This is typical behaviour.
Either you can turn OutputCaching on this page on. This should mean that the browser's second request won't hit your server, and thus only record one entry, but you also need to make sure that you don't have the debug flag set in your web.config file.
The other option is to detect the request type. I think that the first request the browser sends is often a HEAD request and not a GET, or POST. You could detect and handle these appropriately but I think the first option maybe more reliable.
Also, you should really be coding this as a ASPX Handler not a page. This means you could avoid the response.Clear() and thus you don't confuse the browser as to what the content type of the URI is.

Related

How to know that file download is completed in ASP.NET [duplicate]

I have a popup window that displays "Please wait while your file is being downloaded". This popup also executes the code below to start the file download. How can I close the popup window once the file download has completed? I need some way to detect that the file download has completed so I can call self.close() to close this popup.
System.Web.HttpContext.Current.Response.ClearContent();
System.Web.HttpContext.Current.Response.Clear();
System.Web.HttpContext.Current.Response.ClearHeaders();
System.Web.HttpContext.Current.Response.ContentType = fileObject.ContentType;
System.Web.HttpContext.Current.Response.AppendHeader("Content-Disposition", string.Concat("attachment; filename=", fileObject.FileName));
System.Web.HttpContext.Current.Response.WriteFile(fileObject.FilePath);
Response.Flush();
Response.End();
An idea:
If you handle the file downloading yourself in server side code by writing chunk by chunk to the response stream, then you'll know when the file had finished downloading. You would simply have to connect the FileStream to the response stream, send data chunk by chunk, and redirecting after complete. This can be inside your popup window.
Response.ContentType = "application/octet-stream";
Response.AppendHeader("content-disposition", "attachment; filename=bob.mp3");
Response.AppendHeader("content-length", "123456789");
Make sure you check Response.IsClientConnected when writing out to the response stream.
There is a solution where you can track the download status by transferring the file as smaller packets and check whether all the packets have been transferred.
The solution is not mine but you can find it here:
File Download in ASP.NET and Tracking the Status of Success/Failure of Download
//Function for File Download in ASP.Net in C# and
//Tracking the status of success/failure of Download.
private bool DownloadableProduct_Tracking()
{
//File Path and File Name
string filePath = Server.MapPath("~/ApplicationData/DownloadableProducts");
string _DownloadableProductFileName = "DownloadableProduct_FileName.pdf";
System.IO.FileInfo FileName = new System.IO.FileInfo(filePath + "\\" + _DownloadableProductFileName);
FileStream myFile = new FileStream(filePath + "\\" + _DownloadableProductFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
//Reads file as binary values
BinaryReader _BinaryReader = new BinaryReader(myFile);
//Ckeck whether user is eligible to download the file
if (IsEligibleUser())
{
//Check whether file exists in specified location
if (FileName.Exists)
{
try
{
long startBytes = 0;
string lastUpdateTiemStamp = File.GetLastWriteTimeUtc(filePath).ToString("r");
string _EncodedData = HttpUtility.UrlEncode(_DownloadableProductFileName, Encoding.UTF8) + lastUpdateTiemStamp;
Response.Clear();
Response.Buffer = false;
Response.AddHeader("Accept-Ranges", "bytes");
Response.AppendHeader("ETag", "\"" + _EncodedData + "\"");
Response.AppendHeader("Last-Modified", lastUpdateTiemStamp);
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment;filename=" + FileName.Name);
Response.AddHeader("Content-Length", (FileName.Length - startBytes).ToString());
Response.AddHeader("Connection", "Keep-Alive");
Response.ContentEncoding = Encoding.UTF8;
//Send data
_BinaryReader.BaseStream.Seek(startBytes, SeekOrigin.Begin);
//Dividing the data in 1024 bytes package
int maxCount = (int)Math.Ceiling((FileName.Length - startBytes + 0.0) / 1024);
//Download in block of 1024 bytes
int i;
for (i = 0; i < maxCount && Response.IsClientConnected; i++)
{
Response.BinaryWrite(_BinaryReader.ReadBytes(1024));
Response.Flush();
}
//if blocks transfered not equals total number of blocks
if (i < maxCount)
return false;
return true;
}
catch
{
return false;
}
finally
{
Response.End();
_BinaryReader.Close();
myFile.Close();
}
}
else System.Web.UI.ScriptManager.RegisterStartupScript(this, GetType(),
"FileNotFoundWarning","alert('File is not available now!')", true);
}
else
{
System.Web.UI.ScriptManager.RegisterStartupScript(this, GetType(),
"NotEligibleWarning", "alert('Sorry! File is not available for you')", true);
}
return false;
}
Even though this is an old question it hasn't been answered all this time and I believe it deserves a (better) answer:
https://stackoverflow.com/a/59010319/313935
Some hacks are around that involves knowing when the last piece of the buffer has been sent or checking the HttpResponse.IsClientConnected property.
The way to do that is in your pop-up to call the server via AJAX polling for some response which would indicate the file was flushed.
Ex: right before sending the file, store sessionID+FileName in a DB or session or what have you.
On the client, in your popup, poll a web-service via AJAX - this could even be a WebMethod like Bool IsContentFlushed(string sessionID, string fileName);
After you do Response.Flush(); remove this sessionID+FileName from your store.
Call Response.Close() instead of Response.End() - the later is very brutal, and is usually over-kill.
I handle the problem differently in Javascript, which might or might not work for you.
Create a hidden DIV element, with the
message 'File is downloading...'
rather than a pop-up box.
Show the div when the download
starts
Once any other element on the
forms is clicked, hide the div
again..
You could also set a timer to hide
the download message div after so
amount of time...
I figure once the user clicks on another element, she either already knows the download is done, or she is ready to do something else, so the message becomes irrelevant and can go away....

mp3 files not getting downloaded?

I have written the below lines of code in c#
private void DownloadFile(byte[] myData, string Name)
{
Response.Expires = 0;
Response.Clear();
string ext= System.IO.Path.GetExtension(Name);
switch(ext)
{
case ".mp3":
Response.ContentType = "audio/mpeg";
break;
default:
Response.ContentType = "Application/octet-stream";
break;
}
Response.AddHeader("content-length", myData.Length.ToString());
Response.AddHeader("Content-Disposition", "attachment; filename=" + Name);
try
{
Response.BinaryWrite(myData);
}
catch { }
Response.Flush();
Response.End();
}
Now the issue is that whenever we click mp3 file to download, it's directly played. I want that it should download it. Also I want that all types of files should be downloaded.
I struggled with this for the longest time, but finally solved the puzzle. Use Response.WriteFile. You could follow it with Response.Flush but I found that to be unnecessary. Extra headers were not necessary with .mp3 files. In my case, the .mp3 files were in a folder directly under the root. And here's a bonus: The key ingredients for making the .mp3 download work with smartphones (which was my dilemma) were using Response.End, and telling the mobile device that the download was done by sending back the Response.StatusCode = 200.
string FilenameMP3 = "~/someFolder/xyz.mp3";
string headerFilename = Filename.Substring(Filename.IndexOf("/") + 1);
Response.AppendHeader("Content-Disposition", String.Concat("attachment;filename=\"", headerFilename, "\""));
Response.ContentType = "audio/mpeg";
try
{
Response.WriteFile(Filename, true);
Response.End();
}
finally
{
Response.StatusCode = 200;
Response.Close();
}
What you have should be sufficient, assuming that the headers you added aren't being stripped / corrupted in transit (simple to check via Fiddler or similar).
Since you don't want the browser to interpret this data, a pragmatic option might be to simply send all data as "application/octet-stream", regardless of the content. While the "attachment" disposition should be sufficient for this, this approach is explicitly called out in RFC 2616, 19.5.1 ("Content-Disposition"):
If this header is used in a response with the application/octet- stream content-type, the implied suggestion is that the user agent should not display the response, but directly enter a `save response as...' dialog.

Download file in chunks

I've got the problem as below:
There is some SOAP web service which allows to read stream files. I need to read the whole file divided to chunks and transmit to user. All actions should do not block UI main thread: user presses 'Save' button on save file dialog, and is able to move on to the next page or perform another action. I will be grateful for the sample solution. Note that the solution should work with IIS 5.1.
Regards,
Jimmy
Downloading a file in ASP.NET byte-by-byte to the response page. check at msdn about this:
try
{
System.String filename = "C:\\downloadJSP\\myFile.txt";
// set the http content type to "APPLICATION/OCTET-STREAM
Response.ContentType = "APPLICATION/OCTET-STREAM";
// initialize the http content-disposition header to
// indicate a file attachment with the default filename
// "myFile.txt"
System.String disHeader = "Attachment;
Filename=\"myFile.txt\"";
Response.AppendHeader("Content-Disposition", disHeader);
// transfer the file byte-by-byte to the response object
System.IO.FileInfo fileToDownload = new
System.IO.FileInfo(filename);
System.IO.FileStream fileInputStream = new
System.IO.FileStream(fileToDownload.FullName,
System.IO.FileMode.Open, System.IO.FileAccess.Read);
int i;
while ((i = fileInputStream.ReadByte()) != - 1)
{
Response.Write((char)i);
}
fileInputStream.Close();
Response.Flush();
Response.Close();
}
catch (System.Exception e)
// file IO errors
{
SupportClass.WriteStackTrace(e, Console.Error);
}
There are some articles that may help you to implement and solve errors:
download an excel file from byte() on https server
asp.net downloading file from ftp getting it as byte[] then saving it as file
Remote file Download via ASP.NET corrupted file
Response.WriteFile cannot download a large file
ProcessRequest method form downloader HttpHandler:
public void ProcessRequest(HttpContext context)
{
RequestTarget target = RequestTarget.ParseFromQueryString(context.Request.QueryString);
Guid requestId = new Guid(context.Request.QueryString["requestId"]);
string itemName = HttpUtility.UrlDecode(context.Request.QueryString["itemName"]);
if (target != null &&
!requestId.Equals(Guid.Empty) &&
!string.IsNullOrEmpty(itemName))
{
HttpResponse response = context.Response;
response.Buffer = false;
response.Clear();
response.AddHeader("Content-Disposition", "attachment;filename=\"" + itemName + "\"");
response.ContentType = "application/octet-stream";
int length = 100000, i = 0;
byte[] fileBytes;
do
{
fileBytes = WS.ReadFile(requestId, target, i * length, length);
i++;
response.OutputStream.Write(fileBytes, 0, fileBytes.Length);
response.Flush();
}
while (fileBytes != null && fileBytes.Length == length);
}
}
The whole problem is not to organize download action, but satisfy the condition that download action should do not block UI main thread: user presses 'Save' button on save file dialog, and is able to move on to the next page or perform another action. The solution written by Niranjan Kala causes, when the file is very large user isn't able to see another page until the download action has completed. I appreciate it, but it's not what I meant ...
If I understand you correctly, you want to make the browser initiate a new request for the file without reloading the current page. The easiest approach is probably to just create a link with target="_blank". Something like this should do:
Download file
If you provide a content type of application/octet-stream most browsers will save the file to disk.

Download contents of SQL server tables using asp.net c#

// I want to use the SQL Query SELECT * FROM Table here, how can I do that?
string filepath = Server.MapPath("test.doc");
FileInfo file = new FileInfo(filepath);
// Checking if file exists
if (file.Exists)
{
// Clear the content of the response
Response.ClearContent();
// LINE1: Add the file name and attachment, which will force the open/cance/save dialog to show, to the header
Response.AddHeader("Content-Disposition", "attachment; filename=" + file.Name);
// Add the file size into the response header
Response.AddHeader("Content-Length", file.Length.ToString());
// Set the ContentType
Response.ContentType = ReturnExtension(file.Extension.ToLower());
// Write the file into the response (TransmitFile is for ASP.NET 2.0. In ASP.NET 1.1 you have to use WriteFile instead)
Response.TransmitFile(file.FullName);
// End the response
Response.End();
}
Can anyone help me with getting the contents of the table called Table in SQL Server 2008 and downloading it? I have the codes above, but currently it reads from a path, how to make it read from a SELECT query? The query in mind is "SELECT* FROM Table"
One way is to use a SQLDataReader (I'm not going to explain connections etc too here: I assume you've called a database before) and manually concatenate the columns
You'd normally use bcp.exe or perhaps SMO for this.
You could use SqlDataAdapter to fetch the data and populate a DataTable based on the data:
SqlConnection connection = new SqlConnection(connectionString);
string query = "SELECT * FROM Table";
SqlDataAdapter adapter = new SqlDataAdapter(query, connection);
connection.Open();
DataTable table = new DataTable();
try
{
adapter.Fill(table);
}
catch (Exception e)
{
throw e;
}
finally
{
connection.Close();
}
}

How can I detect when a file download has completed in ASP.NET?

I have a popup window that displays "Please wait while your file is being downloaded". This popup also executes the code below to start the file download. How can I close the popup window once the file download has completed? I need some way to detect that the file download has completed so I can call self.close() to close this popup.
System.Web.HttpContext.Current.Response.ClearContent();
System.Web.HttpContext.Current.Response.Clear();
System.Web.HttpContext.Current.Response.ClearHeaders();
System.Web.HttpContext.Current.Response.ContentType = fileObject.ContentType;
System.Web.HttpContext.Current.Response.AppendHeader("Content-Disposition", string.Concat("attachment; filename=", fileObject.FileName));
System.Web.HttpContext.Current.Response.WriteFile(fileObject.FilePath);
Response.Flush();
Response.End();
An idea:
If you handle the file downloading yourself in server side code by writing chunk by chunk to the response stream, then you'll know when the file had finished downloading. You would simply have to connect the FileStream to the response stream, send data chunk by chunk, and redirecting after complete. This can be inside your popup window.
Response.ContentType = "application/octet-stream";
Response.AppendHeader("content-disposition", "attachment; filename=bob.mp3");
Response.AppendHeader("content-length", "123456789");
Make sure you check Response.IsClientConnected when writing out to the response stream.
There is a solution where you can track the download status by transferring the file as smaller packets and check whether all the packets have been transferred.
The solution is not mine but you can find it here:
File Download in ASP.NET and Tracking the Status of Success/Failure of Download
//Function for File Download in ASP.Net in C# and
//Tracking the status of success/failure of Download.
private bool DownloadableProduct_Tracking()
{
//File Path and File Name
string filePath = Server.MapPath("~/ApplicationData/DownloadableProducts");
string _DownloadableProductFileName = "DownloadableProduct_FileName.pdf";
System.IO.FileInfo FileName = new System.IO.FileInfo(filePath + "\\" + _DownloadableProductFileName);
FileStream myFile = new FileStream(filePath + "\\" + _DownloadableProductFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
//Reads file as binary values
BinaryReader _BinaryReader = new BinaryReader(myFile);
//Ckeck whether user is eligible to download the file
if (IsEligibleUser())
{
//Check whether file exists in specified location
if (FileName.Exists)
{
try
{
long startBytes = 0;
string lastUpdateTiemStamp = File.GetLastWriteTimeUtc(filePath).ToString("r");
string _EncodedData = HttpUtility.UrlEncode(_DownloadableProductFileName, Encoding.UTF8) + lastUpdateTiemStamp;
Response.Clear();
Response.Buffer = false;
Response.AddHeader("Accept-Ranges", "bytes");
Response.AppendHeader("ETag", "\"" + _EncodedData + "\"");
Response.AppendHeader("Last-Modified", lastUpdateTiemStamp);
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment;filename=" + FileName.Name);
Response.AddHeader("Content-Length", (FileName.Length - startBytes).ToString());
Response.AddHeader("Connection", "Keep-Alive");
Response.ContentEncoding = Encoding.UTF8;
//Send data
_BinaryReader.BaseStream.Seek(startBytes, SeekOrigin.Begin);
//Dividing the data in 1024 bytes package
int maxCount = (int)Math.Ceiling((FileName.Length - startBytes + 0.0) / 1024);
//Download in block of 1024 bytes
int i;
for (i = 0; i < maxCount && Response.IsClientConnected; i++)
{
Response.BinaryWrite(_BinaryReader.ReadBytes(1024));
Response.Flush();
}
//if blocks transfered not equals total number of blocks
if (i < maxCount)
return false;
return true;
}
catch
{
return false;
}
finally
{
Response.End();
_BinaryReader.Close();
myFile.Close();
}
}
else System.Web.UI.ScriptManager.RegisterStartupScript(this, GetType(),
"FileNotFoundWarning","alert('File is not available now!')", true);
}
else
{
System.Web.UI.ScriptManager.RegisterStartupScript(this, GetType(),
"NotEligibleWarning", "alert('Sorry! File is not available for you')", true);
}
return false;
}
Even though this is an old question it hasn't been answered all this time and I believe it deserves a (better) answer:
https://stackoverflow.com/a/59010319/313935
Some hacks are around that involves knowing when the last piece of the buffer has been sent or checking the HttpResponse.IsClientConnected property.
The way to do that is in your pop-up to call the server via AJAX polling for some response which would indicate the file was flushed.
Ex: right before sending the file, store sessionID+FileName in a DB or session or what have you.
On the client, in your popup, poll a web-service via AJAX - this could even be a WebMethod like Bool IsContentFlushed(string sessionID, string fileName);
After you do Response.Flush(); remove this sessionID+FileName from your store.
Call Response.Close() instead of Response.End() - the later is very brutal, and is usually over-kill.
I handle the problem differently in Javascript, which might or might not work for you.
Create a hidden DIV element, with the
message 'File is downloading...'
rather than a pop-up box.
Show the div when the download
starts
Once any other element on the
forms is clicked, hide the div
again..
You could also set a timer to hide
the download message div after so
amount of time...
I figure once the user clicks on another element, she either already knows the download is done, or she is ready to do something else, so the message becomes irrelevant and can go away....

Categories

Resources