providing dynamic file download in ASP.NET2.0 - c#

I want to provide dynamic download of files. These files can be generated on-the-fly on serverside so they are represented as byte[] and do not exist on disk. I want the user to fill in an ASP.NET form, hit the download button and return the file he/she wanted.
Here is how my code behind the ASP.NET form looks like:
public partial class DownloadService : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void submitButtonClick(object sender, EventArgs e)
{
if (EverythingIsOK())
{
byte[] binary = GenerateZipFile();
Response.Clear();
Response.ContentType = "application/zip";
Response.ContentEncoding = System.Text.Encoding.UTF8;
Response.BinaryWrite(binary);
Response.End();
}
}
...
}
I expected this piece of code just work. I clear the Respone, put in my generated zip file and bingo. However, this is not the case. I get the following message in the browser:
The XML page cannot be displayed
Cannot view XML input using style sheet. Please correct the error and then click the Refresh button, or try again later.
An invalid character was found in text content. Error processing resource 'http://localhost:15900/mywebsite/DownloadS...
What am I doing wrong?

Here's a minor modification you need to make:
Response.Clear();
Response.ContentType = "application/x-zip-compressed";
Response.BinaryWrite(binary);
Response.End();

This is my (working) implementation:
Response.Clear();
Response.ContentType = mimeType;
Response.AddHeader("Content-Disposition", String.Format("attachment; filename=\"{0} {1} Report for Week {2}.pdf\"", ddlClient.SelectedItem.Text, ddlCollectionsDirects.SelectedItem.Text, ddlWeek.SelectedValue));
Response.BinaryWrite(bytes);
Response.Flush();
Response.End();
mimeType is like your application/zip (except PDF).
The main differences are the extra header information passed, and the Flush call on the Response object.

Look here for informationa about application/zip . It might be that the ContentEncoding is wrong. And here's a guide on sending other types. Also here is a guide on how to do it for pdfs.

Related

Download a Large file Async in ASP.NET C#

I have the code below which works well for small files but for large files it generates the zip as required but doesn't download it. I get all sorts of errors including Timeout (which I have managed to resolve). The other problem is that it runs in Sync. The largest file I have generated myself is a 330MB zip file with about 30 HD images attached to it. But this can even go to GBs as the user can choose to download about 100 or even more HD images at once.
To resolve both issues, I thought downloading in async may help in both cases. I want to alert the user that their download has started, and that they will be notified when it is ready.
I am thinking of sending the stream down if the client IsConnected (then delete the file) or sending an email to ask them to download the file if they have decided to logout (then delete the file using the offline download link). I just don't know where or how to write async code, or if what I want to do can actually be done if the user decides to logout.
Here's my current code:
private void DownloadFile(string filePath)
{
FileInfo myfile = new FileInfo(filePath);
// Checking if file exists
if (myfile.Exists)
{
// Clear the content of the response
Response.ClearContent();
// Add the file name and attachment, which will force the open/cancel/save dialog box to show, to the header
Response.AddHeader("Content-Disposition", "attachment; filename=" + myfile.Name);
// Add the file size into the response header
Response.AddHeader("Content-Length", myfile.Length.ToString());
// Set the ContentType
Response.ContentType = "application/octet-stream";
Response.TransmitFile(filePath);
Response.Flush();
try
{
myfile.Delete();
}
catch { }
}
}
I don't know about Async downloads from asp.net applications so I can't address that question. But I have run into enough download issues to always start from the same place.
First, download from a generic handle (ASHX) and not a web form. The webform wants to do extra processing at the end of the request that can cause problems. You question didn't state if you are using a web form or generic handler.
Second, always end the request with the ApplicationInstance.CompleteRequest() method call. Don't use Request.Close() or Request.End()
Those two changes have often cleaned up download issues for me. Try these change and see if you get the same results. Even if you do get the same results this is a better way of coding downloads.
Finally, as an aside, only catch appropriate exceptions in the try-catch bock.
Your code would be like this:
public class Handler1 : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
// set from QueryString
string filePath = "...";
FileInfo myfile = new FileInfo(filePath);
// Checking if file exists
if (myfile.Exists)
{
// Clear the content of the response
context.Response.ClearContent();
// Add the file name and attachment, which will force the open/cancel/save dialog box to show, to the header
context.Response.AddHeader("Content-Disposition", "attachment; filename=" + myfile.Name);
// Add the file size into the response header
context.Response.AddHeader("Content-Length", myfile.Length.ToString());
// Set the ContentType
context.Response.ContentType = "application/octet-stream";
context.Response.TransmitFile(filePath);
context.Response.Flush();
HttpContext.Current.ApplicationInstance.CompleteRequest();
try
{
myfile.Delete();
}
catch (IOException)
{ }
}
}
public bool IsReusable
{
get
{
return false;
}
}
}

Unable to open exported xlsx file

I am trying to export into excel with xlsx format but getting this error when trying to open the file.
Excel cannot open the file 'CertificationMetricsReport.xlsx' because the file format or file extension is not valid. Verify that file has not been corrupted and that the file extension matches the format of the file.
If I will provide the file name CertificationReport.xls then I am able to open it.
Here is the code snippet
public void RenderedReportContent(byte[] fileContent)
{
try
{
Response.Clear();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("Content-Length", fileContent.Length.ToString());
Response.AddHeader("Content-Disposition", "attachment; filename="CertificationReport.xlsx");
Response.BinaryWrite(fileContent);
Response.End();
}
catch (Exception ex)
{
if (!(ex is System.Threading.ThreadAbortException))
{
//Other error handling code here
}
}
}
When I am trying to download CertificationMetricsReport.xls it works fine.
Please help me to download the xlsx file.
maybe you can try to change the contenttype
to contenttype = "application/vnd.ms-excel";
or application/octect-stream
Response.Clear();
Response.Buffer = True;
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment;filename=yourfile.xslx"
Response.BinaryWrite(YourFile);
Response.End();
also you can try with response.flush
at the end try it in others navigators like IE, Chrome, Firefox...
EDIT: http://social.msdn.microsoft.com/forums/en-US/3d539969-51c4-42bc-8289-6d70d8db7aff/prompt-while-downloading-a-file-for-open-or-save
EDIT2: How to send file in HttpResponse?

Trouble cleaning up after serving generated file from asp.net Page_Load

I want to serve a dynamically created binary file from an asp.net web page via a http request parameter like so: www.host.com/?Download=file. So far I have
protected void Page_Load(object sender, EventArgs e)
{
if (Request.Params.Allkeys.Contains("Download"))
{
String fileStr = Request.Params.GetValues("Download")[0];
using (Stream generatedFile = File.Create(#"C:\Temp\file"))
{
/* write the contents of the file */
}
Response.ContentType = "application";
Response.AddHeader("Content-Disposition",
"attachment; filename=" + fileStr);
Response.WriteFile(#"C:\Temp\file");
Response.End();
}
}
which works, but C:\Temp\file still exists and I'd like it cleaned up. Calling File.Delete(#"C:\Temp\file"); after Response.End() doesn't work, since Response.End() kills the thread. Putting the Response methods inside the using block, with File.Create( (...), FileOptions.DeleteOnClose) doesn't work, since the Response methods then fail to get access to the file.
Any suggestions?
After writing file to response you can call Response.Flush to make sure it was fully written, and then delete it before calling Response.End:
Response.WriteFile(#"C:\Temp\file");
Response.Flush();
File.Delete(#"C:\Temp\file");
Response.End();

Response.TransmitFile(filePath) fails in child page in IE

I try to load a small pdf file to client browser. I redirect to download_page.aspx that does the following:
Response.ClearHeaders();
Response.ContentType = "application/pdf";
Response.Clear();
Response.AppendHeader("Content-Disposition", "attachment");
Response.TransmitFile(file);
Response.Flush();
Problem:
When I redirect to download_page.aspx from a link or from a button.OnClientClick="javascript:window.open('download_page.aspx?index=20')"
it works. PDF opens in client browser.
However, when I click on a button that does something on the page and then i use ClientScript.RegisterStartupScript to redirect to download_page.aspx, then download_page.aspx just blinks (flashes) and closes, no pdf loaded.
This is IE7, IE8 problem. It works in Firefox.
Any help appreciated.
Thank you,
Raman.
First of all, you don't need to ClearHeaders Clear and Flush, so your code should look like:
Response.ContentType = "application/pdf";
Response.AppendHeader("Content-Disposition", "attachment");
Response.TransmitFile(file);
Now, you should also improve the Content-Disposition header value and add the file name to ease end-users browser experience. IE is different than other with regards with how the file name can be encoded in case it has special characters, so here is a sample code that you might use or change to your will:
public static void AddContentDispositionHeader(HttpResponse response, string disposition, string fileName)
{
if (response == null)
throw new ArgumentNullException("response");
StringBuilder sb = new StringBuilder(disposition + "; filename=\"");
string text;
if ((HttpContext.Current != null) && (string.Compare(HttpContext.Current.Request.Browser.Browser, "IE", StringComparison.OrdinalIgnoreCase) == 0))
{
text = HttpUtility.UrlPathEncode(fileName);
}
else
{
text = fileName;
}
sb.Append(text);
sb.Append("\"");
response.AddHeader("Content-Disposition", sb.ToString());
}
Now, your code can be written as:
Response.ContentType = "application/pdf";
AddContentDispositionHeader(Response, "attachment", filename);
Response.TransmitFile(file);
The last thing is: make sure nobody deletes the files or writes to it during its transmission.
I met the same condition as yours.
I finally solved it.
Don't use window.open. You can simply use
window.location = 'download_page.aspx?index=20'
Note that the original page will remain well.
Reference from here and from here

Allowing user to download from my site through Response.WriteFile()

I am trying to programatically download a file through clicking a link, on my site (it's a .doc file sitting on my web server). This is my code:
string File = Server.MapPath(#"filename.doc");
string FileName = "filename.doc";
if (System.IO.File.Exists(FileName))
{
FileInfo fileInfo = new FileInfo(File);
long Length = fileInfo.Length;
Response.ContentType = "Application/msword";
Response.AddHeader("Content-Disposition", "attachment; filename=" + fileInfo.Name);
Response.AddHeader("Content-Length", Length.ToString());
Response.WriteFile(fileInfo.FullName);
}
This is in a buttonclick event handler. Ok I could do something about the file path/file name code to make it neater, but when clicking the button, the page refreshes. On localhost, this code works fine and allows me to download the file ok. What am I doing wrong?
Thanks
Rather than having a button click event handler you could have a download.aspx page that you could link to instead.
This page could then have your code in the page load event. Also add Response.Clear(); before your Response.ContentType = "Application/msword"; line and also add Response.End(); after your Response.WriteFile(fileInfo.FullName); line.
Try a slightly modified version:
string File = Server.MapPath(#"filename.doc");
string FileName = "filename.doc";
if (System.IO.File.Exists(FileName))
{
FileInfo fileInfo = new FileInfo(File);
Response.Clear();
Response.ContentType = "Application/msword";
Response.AddHeader("Content-Disposition", "attachment; filename=" + fileInfo.Name);
Response.WriteFile(fileInfo.FullName);
Response.End();
}
Oh, you shouldn't do it in button click event handler. I suggest moving the whole thing to an HTTP Handler (.ashx) and use Response.Redirect or any other redirection method to take the user to that page. My answer to this question provides a sample.
If you still want to do it in the event handler. Make sure you do a Response.End call after writing out the file.

Categories