You se finally I have 2 datatables filled with different data, now I have a button that allows me to send one datatable to a .CSV Excel file like this:
string name="Dat_Agrup";
HttpContext context = HttpContext.Current;
context.Response.Clear();
foreach (System.Data.DataColumn column in _myDataTable.Columns)
{
context.Response.Write("name"+ ",");
}
context.Response.Write(Environment.NewLine);
foreach (System.Data.DataRow row in _myDataTable.Rows)
{
for (int i = 0; i < _myDataTable.Columns.Count; i++)
{
context.Response.Write(row[i].ToString().Replace(",", string.Empty) + ",");
}
context.Response.Write(Environment.NewLine);
}
context.Response.ContentType = "text/csv";
context.Response.AppendHeader("Content-Disposition", "attachment; filename=" + name + ".csv");
context.Response.End();
Now this code works perfect it maybe missing some lines like where I declare the datatable but just trust me it works :D, now if I want to save the second datatable using the same code in the same action_button is those not work, i use this next code:
string name2="Centroids";
HttpContext context2 = HttpContext.Current;
context2.Response.Clear();
foreach (System.Data.DataRow row in _myDataTable2.Rows)
{
for (int i = 0; i < _myDataTable2.Columns.Count; i++)
{
context2.Response.Write(row[i].ToString().Replace(",", string.Empty) + ",");
}
context2.Response.Write(Environment.NewLine);
}
context2.Response.ContentType = "text2/csv";
context2.Response.AppendHeader("Content-Disposition", "attachment; filename=" + name2 + ".csv");
context2.Response.End();
It only save the first datatable and ignores the rest of the code can anyone explain the reason or why this happens, much appreciated any kind of help.
The reason is this line in your first code snippet:
context.Response.End();
The HttpResponse.End() method "stops execution of the page, and raises the EndRequest event."
If you'd like to continue processing the code, you can't call that method until the end.
Related
I have two reports that download excel files when the user clicks the export button. Both of them use the same method in an external library (shown below). One of the reports opens the excel sheet normally with the generated data while the other shows the source page design inside the excel sheet. This happens in VS2008.
What is going on, and how to solve it?
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.Buffer = true;
HttpContext.Current.Response.ContentType = "application/ms-excel;";
HttpContext.Current.Response.BinaryWrite(System.Text.Encoding.UTF8.GetPreamble());
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=Report.xls");
HttpContext.Current.Response.Charset = "utf-8";
HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.UTF8;
HttpContext.Current.Response.Write(#"<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.0 Transitional//EN"">");
//sets font
HttpContext.Current.Response.Write("<font style='font-size:10.0pt; font-family:Calibri;'>");
if (addCurrentDate)
HttpContext.Current.Response.Write("<h5 align='left'>" + DateTime.Now.ToString() + "</h5>");
HttpContext.Current.Response.Write("<h2>" + title + "</h2>");
string subttitlesString = string.Empty;
if (subItems != null && subItems.Count > 0)
{
subttitlesString = "<table>";
foreach (var item in subItems)
{
subttitlesString += string.Format("<tr><td style='font-weight:bold;'>{0}</td><td>{1}</td></tr>", item.Key, item.Value);
}
subttitlesString += "</table>";
HttpContext.Current.Response.Write(subttitlesString);
}
//sets the table border, cell spacing, border color, font of the text, background, foreground, font height
HttpContext.Current.Response.Write("<Table border='1' bgColor='#ffffff' " +
"borderColor='#000000' cellSpacing='0' cellPadding='0' " +
"style='font-size:10.0pt; font-family:Calibri; background:white;'> <TR>");
//am getting my grid's column headers
int columnscount = table.Columns.Count;
for (int j = 0; j < columnscount; j++)
{ //write in new column
HttpContext.Current.Response.Write("<Td>");
//Get column headers and make it as bold in excel columns
HttpContext.Current.Response.Write("<B>");
HttpContext.Current.Response.Write(table.Columns[j].ColumnName.ToString());
HttpContext.Current.Response.Write("</B>");
HttpContext.Current.Response.Write("</Td>");
}
HttpContext.Current.Response.Write("</TR>");
foreach (DataRow row in table.Rows)
{//write in new row
HttpContext.Current.Response.Write("<TR>");
for (int i = 0; i < table.Columns.Count; i++)
{
HttpContext.Current.Response.Write("<Td>");
HttpContext.Current.Response.Write(row[i].ToString());
HttpContext.Current.Response.Write("</Td>");
}
HttpContext.Current.Response.Write("</TR>");
}
HttpContext.Current.Response.Write("</Table>");
HttpContext.Current.Response.Write("</font>");
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.End();
Is this code surrounded by try-catch? May be for code that is rendering source page, you are getting exception somewhere, which is resulting in HTML of source page being rendered. Any ways, why are you writing HTML as application/ms-excel?
I found the cause of this, which is quite obvious now.
The calling event of the above exporting method has two catch sections:
ThreadAbortException
Exception
The ThreadAbortException part had Thread.ResetAbort() because the ThreadAbortException keeps re-throwing itself. This seems to reset all the HTTPRespnse content that was previously added.
I have 5 DataTables that needs to be converted to TXT files. Instead of creating them separately, I thought I use a for loop. Here's my code:
StringBuilder sb = new StringBuilder();
for (int i = 1; i < 5; i++)
{
DataTable dtFile1 = file1BLO.SelectFile1ForCSV()
foreach (DataRow dr in dtFile1.Rows)
{
string[] fields = dr.ItemArray.Select(field => field.ToString()).ToArray();
sb.AppendLine(string.Join("|", fields) + "|");
}
Response.ContentType = "application/text";
Response.AddHeader("content-disposition", "attachment;filename=CAPRES-FILE1-"
+ DateTime.Now.ToString("yyyyMMdd-HHmmss") + ".txt");
Response.Output.Write(sb);
Response.Flush();
Response.End();
sb.Clear();
}
I would want the iterator to be appended to the variable names and methods. Like this DataTable dtFile + i = file + i + BLO.SelectFile + i + ForCSV();
Thanks!
Requested Code for SelectFile1ForCSV()
public DataTable SelectFile1ForCSV()
{
return file1DAO.SelectFile1ForCSV();
}
EDIT: I am sorry, it seems that I haven't provided enough details, and my question has caused confusion. Edited now.
You cannot just append a number to a variable name at runtime to magically reference a new variable. What you should do instead is:
Define an an interface:
public interface IFileBLO
{
DataTable SelectFileForCSV();
}
Have File1BLO, File2BLO etc all implement IFileBLO and fix the method names so that they are all SelectFileForCSV rather than SelectFile1ForCSV etc.
Add a lookup for reference these objects:
var bloList = new IFileBLO[]
{
file1BLO, file2BLO, file3BLO, file4BLO, file5BLO
};
Finally, change your loop to:
for (int i = 0; i < 5; i++)
{
var dtFile = bloList[i].SelectFileForCSV();
foreach (var dr in dtFile.Rows)
{
...
There are not enough information in the question to know exactly what the problem is, so I'm just guessing here. Your problem is that you have five objects, that all have a method, and these method have different names. The methods return the same thing, though, DataTable, that can be used in a loop.
If that's the case then just take out of the loop that which is different, so that in the loop remains that which is identical. Something like this:
DataTable[] fiveTables =
{
file1BLO.SelectFile1ForCSV(),
file2BLO.SelectFile2ForCSV(),
file3BLO.SelectFile3ForCSV(),
file4BLO.SelectFile4ForCSV(),
file5BLO.SelectFile5ForCSV()
}
for (int i = 1; i <= 5; i++)
{
// Use fiveTables[i] for DataTable, and i for file name
}
Use this:
Response.AddHeader("content-disposition", "attachment;filename=CAPRES-FILE"
+ i
+ "-"
+ DateTime.Now.ToString("yyyyMMdd-HHmmss") + ".txt");
This will create a filename containing the value of i.
Having some trouble exporting to downloadable Excel content, using AngularJS & ASP.NET MVC. My end results is nothing happens.
Sample ASP.NET Controller method:
[HttpPost]
public ActionResult ExportToExcel(Model form)
{
var gv = new GridView();
gv.DataSource = _service.getSomeStuff(form);
gv.DataBind();
Response.ClearContent();
Response.Buffer = true;
Response.AddHeader("content-disposition", "attachment; filename=Stuff.xls");
Response.ContentType = "application/ms-excel";
Response.Charset = "";
var sw = new StringWriter();
var htw = new HtmlTextWriter(sw);
gv.RenderControl(htw);
Response.Output.Write(sw.ToString());
Response.Flush();
Response.End();
byte[] temp = System.Text.Encoding.UTF8.GetBytes(sw.ToString());
return File(temp, "application/ms-excel");
}
Angular Controller Method: -> triggered via ng-click handler
function exportToExcel() {
$http.post('/Controller/ExportToExcel/', vm.Model)
.success(function (data) {
})
.error(function (data) {
alerts.error(data);
});
}
View:
click me
Any suggestions of what I might be doing wrong?
I have done something like this, without the need for AJAX or any JS. Tweaking the Razor code is all that is required.
Secondly, my personal suggestion would be to not convert to Excel file at all. The reason being, the user is required to have Office on his local machine. It also means, should you upload your project to a website, that server machine will need Office installed in order to produce your excel file.
That being said, I would suggest just using a CSV file. If a user has Office installed, they would be able to use Excel to view the file like any spreadsheet.
Here is some code that will create a CSV called Export.csv from a dbset in your dbcontext, done using StringBuilder and Reflection.
public ActionResult Export()
{
StringBuilder str = new StringBuilder();
var tmp = db.Users.FirstOrDefault();
Type comp = tmp.GetType(); // get type
foreach (PropertyInfo prop in comp.GetProperties())
{
str.Append(prop.Name + ","); //set column names
}
str.Replace(",", "\n", str.Length - 1, 1);
foreach (object item in db.Users)
{
foreach (PropertyInfo prop in item.GetType().GetProperties())
{
try
{
string a = prop.GetValue(item, null).ToString();
str.Append(a + ",");
}
catch (NullReferenceException)
{
str.Append("null" + ","); //for nulls, append string with "null"
}
}
str.Replace(",", "\n", str.Length - 1, 1);
}
string csv = str.ToString();
return File(new System.Text.UTF8Encoding().GetBytes(csv), "text/csv", "Export.csv");
}
You can then access download the file with a link on your view like this:
click me
Hope this helps.
public static void ExportToExcel(DataTable dtExcel, string fileName)
{
string attachment = "attachment; filename=" + fileName + ".xlsx";
System.Web.HttpContext.Current.Response.ClearContent();
System.Web.HttpContext.Current.Response.AddHeader("content-disposition", attachment);
System.Web.HttpContext.Current.Response.ContentType = "application/vnd.ms-excel";
//System.Web.HttpContext.Current.Response.ContentType = "application/excel";
//System.Web.HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
//System.Web.HttpContext.Current.Response.ContentType = string.Empty;
string tab = "";
foreach (DataColumn dc in dtExcel.Columns)
{
System.Web.HttpContext.Current.Response.Write(tab + dc.ColumnName);
tab = "\t";
}
System.Web.HttpContext.Current.Response.Write("\n");
int i;
foreach (DataRow dr in dtExcel.Rows)
{
tab = "";
for (i = 0; i < dtExcel.Columns.Count; i++)
{
System.Web.HttpContext.Current.Response.Write(tab + dr[i].ToString());
tab = "\t";
}
System.Web.HttpContext.Current.Response.Write("\n");
}
System.Web.HttpContext.Current.Response.Flush();
System.Web.HttpContext.Current.Response.Close();
}
Above code snippet generate only .xls format .If i change response time and File-name extension to .xlsx it does not work .Is there any other approach to do the same.
As per suggestion i have changed approach and generating .xlsx using openxml library.
But it throws error Unable to determine the identity of domain while generating large xlsx file.Please help
public static void ExportToexcel(DataTable dtExcel, string fileName)
{
System.Web.HttpContext.Current.Response.ClearContent();
OpenXMLOffice openxmloffice = new OpenXMLOffice();
MemoryStream msXML = openxmloffice.DataTableToMemoryStream(dtExcel);
msXML.Seek(0, SeekOrigin.Begin);
msXML.WriteTo(System.Web.HttpContext.Current.Response.OutputStream);
System.Web.HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
System.Web.HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=DataTable.xlsx");
System.Web.HttpContext.Current.Response.StatusCode = 200;
System.Web.HttpContext.Current.Response.Flush();
System.Web.HttpContext.Current.Response.Close();
}
The fastest and most reliably method is to use a library like epplus, whcih even has methods like toDatatTable() and FromDataTable()
http://epplus.codeplex.com/
I have a project which should include a download function whereby when the user press the download button, the contents of the SQL Server table will be downloaded as a csv file.
Is there any way I can do this?
The contents of the table called Characters will be downloaded as a csv file. What I know is that I have use the query Select* from Characters, but I do not know how to implement it.
protected void btnDownload_Click(object sender, EventArgs e)
{
string fileName = string.Empty;
string filepath = Request.MapPath("~/Uploads");// this needs to be changed with the SQL query, but I do not know how to implement it
string downloadFileName = "Attendance.zip";
Response.ContentType = "application/zip";
Response.AddHeader("content-disposition", "filename=" + downloadFileName);
using (ZipFile zip = new ZipFile())
{
foreach (GridView row in gvFiles.Rows)
{
CheckBox cb = (CheckBox)row.FindControl("chkSelect");
if (cb != null && cb.Checked)
{
fileName = (row.FindControl("lblFileName") as Label).Text;
zip.AddFile(Server.MapPath(Path.Combine(filepath, fileName)), "");
}
}
zip.Save(Response.OutputStream);
}
I'm not sure how the code you posted relates to the problem, but here's how you can take the contents of a table and turn it into a CSV file. The sample assumes you have an already filled DataTable (dtTable):
StringBuilder sb = new StringBuilder();
for (int i = 0; i < dtTable.Columns.Count; i++)
{
sb.Append(dtTable.Columns[i].ColumnName);
sb.Append(",");
}
// Remove the trailing ,
sb.Remove(sb.Length - 1, 1);
sb.Append(Environment.NewLine);
for (int i = 0; i < dtTable.Rows.Count; i++)
{
for (int j = 0; i < dtTable.Columns.Count; j++)
{
sb.Append(dtTable.Rows[i][j].ToString());
sb.Append(",");
}
sb.Remove(sb.Length - 1, 1);
sb.Append(Environment.NewLine);
}
string csvFileString = sb.ToString();
For performance and economy of resource use, I would use a SQL Command and a forward-only SqlDataReader to get the data.
These articles might help you understand what's required.:
http://www.developerfusion.com/article/4278/using-adonet-with-sql-server/2/
http://wiki.asp.net/page.aspx/401/export-to-csv-file/
You havn't told much about your environment. For example:
Which data access technology do you use ?
Do you have to escape the fields in your csv file?
For dealing with csv files i recommend using the filehelpers library.
If you are free in choosing data access, maybe you should take a look at LINQ2SQL or ADO EF or just use plain SqlCommand/SqlDataReader.