How to download a generated excel file from your asp.net application - asp.net

I am building an asp.net website and I am constructing a Excel document based on some gridview data. I am using Microsoft.Office.Interop.Excel to construct it. I have tried to use a saveFileDialog box using System.Windows.Forms. Through my research online, I have learned that you can’t actually do this in an asp.net application? Everything works great in debugging mode, but when uploading it to the site, the page doesn't work at all. So my man question is, is it possible to to use a saveFileDialog box for an asp.net application? Does anyone know a good workaround for this? I will post my code that works great in debugging mode, but doesn't work when I upload it to my site. Thanks in advance for any help.
using System.Threading;
using Excel = Microsoft.Office.Interop.Excel;
using Microsoft.Office.Interop.Excel;
using System.Windows.Forms;
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
Excel.Application xlApp = new Excel.Application();
Excel.Workbook xlWorkBook;
Excel.Worksheet xlWorkSheet;
object misValue = System.Reflection.Missing.Value;
public void someEvent()
{
var t = new Thread(SaveFolder);
t.IsBackground = true;
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
public void SaveFolder()
{
saveFileDialog1.Filter = "Sources (*.xls, *.xlsx)|*.xls*;*.xlsx";
saveFileDialog1.ShowDialog();
exportReport();
}
public void exportReport()
{
xlWorkBook.SaveAs(#saveFileDialog1.FileName, Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue);
xlWorkBook.Close(true, misValue, misValue);
xlApp.Quit();
releaseObject(xlApp);
releaseObject(xlWorkBook);
releaseObject(xlWorkSheet);
}
public void releaseObject(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
}
catch (Exception ex)
{
obj = null;
MessageBox.Show("Unable to release the Object " + ex.ToString());
}
finally
{
GC.Collect();
}
}

You can't do what you want to with the save dialog. You should just save the file to a temporary location on your server. Once you have the file saved somewhere, you can force the file at the user for download. I usually follow this code (seems to work in all browsers the most consistently). You have to supply the filename and yourFileByteArray variables.
Response.Buffer = true;
Response.Clear();
Response.ClearHeaders();
Response.ContentType = "application/vnd.ms-excel";
Response.CacheControl = "public";
Response.AddHeader("Pragma", "public");
Response.AddHeader("Expires", "0");
Response.AddHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
Response.AddHeader("Content-Description", "Excel File Download");
Response.AddHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
Response.BinaryWrite(yourFileByteArray);
Response.Flush();
Response.End();
There are several ways to get your file as a byte array, but I'll leave that as an exercise for you.

Don't use Interop. Suggest using a mix of HtmlTextWriter, StringWriter, and your GridView.
public void GridViewToExcel()
{
Response.Clear();
Response.AddHeader("content-disposition", "attachment;filename=MyFile.xls");
Response.Charset = "";
Response.ContentType = "application/vnd.xls";
var writer = new System.IO.StringWriter();
var htmlWriter = new HtmlTextWriter(writer);
GridView1.RenderControl(htmlWriter);
Response.Write(writer.ToString());
Response.End();
}

You can't show a dialog box on the server. There's nobody there to see it. Get rid of the whole saveFileDialog object and just call SaveAs with a generated filename in the server's file system that is guaranteed to be unique. Then transmit that file to your user.

Related

I can't open .pdf, .doc etc. file from other servers via SFTP using rebex

I have Two different servers as like below.
1. WebServer - Where is my application is locate
2. FileServer - where is my all uploaded files are locate in perticular location / Folder
Now in my web application I have created one page which display all uploaded files from FileServer (which i have uploaded).
But the issue is, when I try to open/read that file then I am not able. I have all rights of SFTP. and I am getting below issue in Try-catch block.
"Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack."
I have used REBEX for upload and download files.
Note : I can able to open simple text file (.txt) but not other formated files like (.PDF, .docx, .jpg etc.)
My file read code is like below.
protected void LinkButton1_Click(object sender, EventArgs e)
{
try
{
LinkButton lbtn = (LinkButton)sender;
using (Sftp _sftp = new Sftp())
{
_sftp.Connect(serverNm, 22);
_sftp.Login(username, password);
_sftp.ChangeDirectory(currentDirectory);
Stream stream = _sftp.GetStream(lbtn.ToolTip.ToString(), FileMode.Open, FileAccess.Read);
StreamReader sourceStream = new StreamReader(stream);
Byte[] buffer = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());
Response.Buffer = true;
if (lbtn.ToolTip.IndexOf(".pdf") > 0)
{
Response.ContentType = "application/pdf";
}
else if (lbtn.ToolTip.IndexOf(".txt") > 0)
{
Response.ContentType = "text/plain";
}
else if (lbtn.ToolTip.IndexOf(".xls") > 0)
{
Response.ContentType = "application/ms-excel";
}
else if (lbtn.ToolTip.IndexOf(".doc") > 0)
{
Response.ContentType = "application/msword";
}
else if (lbtn.ToolTip.IndexOf(".jpeg") > 0)// || lbtn.ToolTip.IndexOf(".jpg") > 0)
{
Response.ContentType = "image/jpeg";
}
else if (lbtn.ToolTip.IndexOf(".jpg") > 0)
{
Response.ContentType = "image/jpg";
}
else if (lbtn.ToolTip.IndexOf(".bmp") > 0)
{
Response.ContentType = "image/png";
}
Response.AddHeader("Content-Length", "attachment;filename=" + buffer.Length.ToString());
Response.BinaryWrite(buffer);
Response.End();
}
}
catch (Exception ex)
{
}
}
So any one can help to fixe this issue.
I am using latest Mozila browser.
Thank you.
Would it be possible to post the complete stack trace of the exception here? You can get the stack trace by modifying the catch block like this:
try
{
//... your code
}
catch (Exception ex)
{
Response.ContentType = "text/plain";
Response.Write(ex.ToString());
Response.End();
}

"server cannot append header after http headers have been sent"

i have application like email messaging system. here i adjust one solution to download all file that are in table from particular post.
this is my code:
protected void lbu_download_all_Click(object sender, EventArgs e)
{
if (rpt_file_list.Items.Count > 0)
{
using (DataClassesDataContext db = new DataClassesDataContext())
{
var query = from f in db.Files
where f.Post_History_id == int.Parse(post_id.Value.ToString())
select new
{
FileName = f.File_name,
File_ext= f.File_ext
};
foreach (var item in query)
{
System.IO.FileInfo objFile = new FileInfo(Server.MapPath("~/PostFiles/" + item.FileName.ToString() + item.File_ext.ToString()));
if (objFile.Exists)
{
Response.Clear();
string strFileName = item.FileName.ToString() + item.File_ext.ToString();
Response.AddHeader("Content-Disposition", "attachment; filename=" + strFileName);
Response.AddHeader("Content-Length", objFile.Length.ToString());
Response.ContentType = "application/octet-stream";
Response.WriteFile(objFile.FullName);
Response.BufferOutput = true;
Response.Flush();
}
}
}
}
else
{
StringBuilder sb = new StringBuilder();
sb.Append("<script type = 'text/javascript'>");
sb.Append(" No files found to download');");
sb.Append("</script>");
ClientScript.RegisterStartupScript(this.GetType(), "script", sb.ToString());
}
}
i don't know what is problm please help me..
You won't be able to download multiple files like that, I imagine what is happening is that the loop goes through once and on the second iteration it then throws the exception.
What you really should be doing is zipping all the files into one file to download, this question should give you an idea of what I mean.
By zipping the file you'll also get the benefit of compression (less bandwidth, faster transfer) and the user (in your current scenario) won't be presented with multiple 'Save As' dialog windows (much more professional!).
This link may also help you with some other potential ideas (like having a 'Download' page with URL parameters to identify the file). I'm more a fan of a zipped single file option though!
Do you have Response.BufferOutput = true; set properly? If not, the page will be sent as it is generated, which means the Response.Clear() won't do what you want :)

File Download inside iframe

I'm using following method to download a file.on a button click inside a iframe.it's working fine in every browser except IE.can some one plz suggest me a sollution
private void DownloadToBrowser(string filePath)
{
try
{
FileInfo file = new FileInfo(filePath);
Context.Response.Clear();
Context.Response.ClearHeaders();
Context.Response.ClearContent();
Context.Response.AddHeader("Content-Disposition", "attachment; filename=" + file.Name);
Context.Response.AddHeader("Content-Length", file.Length.ToString());
Context.Response.ContentType = "text/plain";
Context.Response.Flush();
Context.Response.TransmitFile(file.FullName);
Context.Response.End();
}
catch (Exception ex)
{
throw ex;
}
}
I would suggest removing the Context.Response.Flush(); line... I don't think it's necessary (as it will happen as part of Context.Response.End(); line), and maybe messing up how the browser receives the file on the next line.
Also, is the file you're transmitting definitely a plain-text file? If not, you'll need to provide a different Context.Response.ContentType();
You have most probably missed some HTTP response headers required by IE.
There is KB on microsoft web.
Also take a look at similar question on SO : PHP script to download file not working in IE
You could try something like this :
Context.Response.Buffer = true;
Context.Response.ContentType = "application/pdf";
Context.Response.AddHeader("Content-Disposition", "attachment;filename=" + FileName );
Context.Response.OutputStream.Write(dataBytes ,0,FileContentLength);
Also try adding this to your aspx page :
<%# Page aspCompat="True" other attributes %>
For Understanding I m using Dataset,
For download as a Excel File
Use Namespace:
using System.IO;
using System.Data;
DataSet ds = new DataSet("Table");
ds.Tables.Add("Table1");
ds.Tables[0].Columns.Add("Field1");
ds.Tables[0].Columns.Add("Field2");
ds.Tables[0].Columns.Add("Field3");
ds.Tables[0].Rows.Add();
ds.Tables[0].Rows[0][0] = "1";
ds.Tables[0].Rows[0][1] = "2";
ds.Tables[0].Rows[0][2] = "3";
HttpResponse response = HttpContext.Current.Response;
// first let's clean up the response.object
response.Clear();
response.Charset = "";
// set the response mime type for excel
response.ContentType = "application/vnd.ms-excel";
response.AddHeader("Content-Disposition", "attachment;filename=sample.xls");
// create a string writer
using (StringWriter sw = new StringWriter())
{
using (HtmlTextWriter htw = new HtmlTextWriter(sw))
{
// instantiate a datagrid
DataGrid dg = new DataGrid();
dg.DataSource = ds.Tables[0];
dg.DataBind();
dg.RenderControl(htw);
response.Write(sw.ToString());
response.End();
}
}
For Download as a Word File
Replace
response.ContentType = "application/msword";
response.AddHeader("Content-Disposition", "attachment;filename=sample.doc");

Responding with a csv file in asp.net

I am trying to make a csv file from a textbox and then send it to the user. This is my code so far:
Response.Clear();
Response.ContentType = "text/csv";
Response.AppendHeader("Content-Disposition",
string.Format("attachment; filename={0}", DateTime.Now));
Response.Write(TextBox_Data.Text);
Context.Response.End();
What is sent is an empty xml file, I have never tried responding with a file before and I'm wondering why it does this?
I have also tried the following which did not work:
var writer = File.CreateText("C:\\file.csv");
writer.WriteLine(TextBox_Data.Text);
Context.Response.Clear();
Context.Response.AppendHeader("content-disposition", "attachment; filename=" + DateTime.Now + ".csv");
Context.Response.ContentType = "text/csv";
Context.Response.Write("C:\\file.csv");
Context.Response.Flush();
Context.Response.End();
Let me know if you have the answer :)
The following code worked for me. You may just be missing a file extension.
Response.Clear();
Response.ContentType = "text/csv";
Response.AppendHeader("Content-Disposition",
string.Format("attachment; filename={0}.csv", DateTime.Now));
Response.Write(TextBox_Data.Text);
Context.Response.End();
Just a complement on joshb's answer regarding the use of Response.End():
MSDN does not recommend the use of Response.End() for non-error cases, and in some cases it can actually cause the client to lose some data .
In my case sometimes the downloaded csv would loose the last bytes of the last line, so I removed the Response.End() and used
HttpContext.Current.ApplicationInstance.CompleteRequest()
instead, and I had to override the page's Render(HtmlTextWriter writer) method to not write anything on the request, since the csv was already writen.
public class PageBase : Page
{
private bool performRegularPageRender = true;
protected override void Render(HtmlTextWriter writer)
{
if (performRegularPageRender)
base.Render(writer);
}
public void SkipRegularPageRendering()
{
performRegularPageRender = false;
}
}
More info / credits:
msdn blog; Is Response.End() considered harmful?; PostBack and Render Solutions? Overrides

Problem downloading a 25MB file - the 8MB file downloads without problem (ASP.NET)

I have two files at the same location but the big one, when is about to finish download, gives an error (both in IE and Firefox).
I use the following code:
public static void DownloadZipFile (string filename, bool notifyMe)
{
HttpContext context = HttpContext.Current;
HttpServerUtility server = context.Server;
bool ok = false;
try
{
string file = string.Format ("~/contents/licensing/members/downloads/{0}", filename);
string server_file = server.MapPath (file);
HttpResponse response = context.Response;
//response.BufferOutput = false;
response.ContentType = "application/zip";
string value = string.Format ("attachment; filename={0}", filename);
response.AppendHeader ("Content-Disposition", value);
FileInfo f = new FileInfo (server_file);
long size = f.Length;
response.TransmitFile (server_file, 0, size);
response.Flush ();
ok = true;
response.End ();
}
catch (Exception ex)
{
Utilities.Log (ex);
}
finally
{
if (ok && notifyMe)
NotifyDownload (filename);
}
}
Any ideas?
Response.End() calls Response.Flush(). Try removing the Flush call.
The solution to this problem is to add the line:
response.AddHeader("Content-Length",size.ToString());
before the call to TransmitFile ().
The credits go to Jim Schubert (see his comment above).

Resources