I'm using this function to create an Excel file from my SQL Server query
DataTable dt = new DataTable();
SqlConnection objcon = new SqlConnection(connectionString);
string sql = "My SELECT SQL";
SqlDataAdapter objda = new SqlDataAdapter(sql, objcon);
objda.Fill(dt);
GridView gvreport = new GridView();
gvreport.DataSource = dt;
gvreport.DataBind();
string fileName = string.Format("fileNameHere");
Response.ClearContent();
Response.AddHeader("content-disposition", "attachment; filename=" + fileName);
Response.ContentType = "application/excel";
System.IO.StringWriter sw = new System.IO.StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
gvreport.RenderControl(htw);
Response.Write(sw.ToString());
Response.End();
return null;
Which worked great until I now realized that it does not work so well when its trying to write over 11,000 rows.
The Excel file itself is fine but after around 11,000 rows it suddenly breaks during one and after that all rows are blank. The rows themselves are still "created" with an border and everything but they are all blank.
Any idea what is causing this? Or is there any better way to create an Excel file like this?
Well, in your case you are not actually generating a real Excel file, just plain HTML and telling Excel to open it and convert it. You may encounter other problems using this approach with OpenOffice or LibreOffice or any other tool that actually expects a real Excel file.
I would look into a more robust solution, by using either OpenXml directly, or indirectly through ClosedXml or some other similar component.
For example, if you were to use ClosedXml, you can do something like this:
var wb = new XLWorkbook();
var dataTable = GetTable("Information");
// Add a DataTable as a worksheet
wb.Worksheets.Add(dataTable);
wb.SaveAs("AddingDataTableAsWorksheet.xlsx");
Extracted from: https://closedxml.codeplex.com/wikipage?title=Adding%20DataTable%20as%20Worksheet
However, in your case instead of saving to a physical file you'd output the stream directly to the Response.
Related
I want to make a button that makes the download of a DataTable object using an HTTP request.
I already have this code that can print .xls files by changing the contentType as indicated in comment.
However, this does not work with xlsx file.
private void DownloadExcel(DataSet ds, string excelFileNameNowDateTime)
{
System.IO.StringWriter tw = new System.IO.StringWriter(); ;
System.Web.UI.HtmlTextWriter hw = new System.Web.UI.HtmlTextWriter(tw);
System.Web.UI.WebControls.DataGrid dgGrid = new System.Web.UI.WebControls.DataGrid();
dgGrid.DataSource = ds.Tables[0];
// Get the HTML for the control.
dgGrid.HeaderStyle.Font.Bold = false;
dgGrid.DataBind();
dgGrid.RenderControl(hw);
string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
//string contentType = "application/vnd.ms-excel";
Response.ContentType = contentType;
this.EnableViewState = true;
Response.Clear();
//Response.ContentEncoding = System.Text.Encoding.Default;
Response.AddHeader("content-disposition", String.Format(#"attachment; filename={0}", excelFileNameNowDateTime + ".xlsx"));
Response.Write(tw.ToString());
CloseHTTPResponse();
}
While opening the file is giving me the error
Excel cannot open the file .xlsx because the file format is not valid. Verify that the file has not been corrupted and that the file extension matches the format of the file.
Any idea on why this does not work?
It looks to me like you're trying to send HTML contents with .xlsx extension. This won't work since XLSX is fundamentally not HTML, but zipped XML with quite specific (and convoluted) schema. The simplest way to achieve your goal would be to use one of the existing 3rd party libraries that can generate XLSX on the fly. I personally had used ClosedXML for a similar task, but there are many other options at NuGet.
This code doesn't produce an Excel file, it produces an HTML file with a fake extension. Excel won't be fooled, it will try to import this HTML file using the user locale's defaults. This will easily lead to problems if the decimal separator is different or the cells contain text that interferes with HTML.
There's no reason for such code. XLSX is a ZIP package containing well-formed XML files. You can use the Open XML SDK to create Excel files at a low level or you can use libraries like EPPlus (57M downloads), ClosedXML (27M), NPOI (22M) and more, to create real Excel files.
With EPPlus, creating an Excel file from a DataTable is really a single command, sheet.Cells.LoadFromDataTable(dt);
public byte[] Export(DataTable dt)
{
using (var p = new ExcelPackage())
{
var ws = p.Workbook.Worksheets.Add("SomeSheet");
var table=ws.Cells.LoadFromDataTable(dt);
var excelData = package.GetAsByteArray();
return excelData;
}
}
After that, you write the output to the Response stream :
var bytes = Export(dt);
Response.Clear();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("Content-Disposition", $"attachment;filename={excelFileNameNowDateTime}.xlsx");
Response.BinaryWrite(bytes);
Response.End();
For ASP.NET (no .NET Core Required solution).
using ClosedXML.Excel;
private void DownloadExcelClosedXML(DataTable dt)
{
using (var workbook = new XLWorkbook())
{
var worksheet = workbook.Worksheets.Add(dt);
using (var stream = new MemoryStream())
{
workbook.SaveAs(stream);
var content = stream.ToArray();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheet.sheet";
Response.AddHeader("content-disposition", "attachment; filename=name_you_file.xlsx");
Response.BinaryWrite(content);
Response.End();
}
}
}
I have to store around 315k rows of data with 15 columns per row in an excel and make it available for download. I am retrieving all the data and then storing it in a Data Table and then using the OpenXml to write it to a workbook and send the response. But I get a exception System.OutOfMemoryException exception due to the huge volume of data.
When I tried it by retrieving around 100k records the whole this worked fine without any error.
I have seen similar question here on SO but it was with a FileStream and hence the size of the MemoryStream was set dynamically like
MemoryStream memory = new MemoryStream(fileStream.size())
I was wondering if there was a way to do this with DataTable too. I believe updating the excel sheet row by row would be a option but that would include a lot of code for checking the datatype and such.
Also, I faced a lot of issue with "File being corrupt" by working with that. Hence, I prefer a xlsx file.
protected void DownloadDetailTable_OnClick(object sender, EventArgs e)
{
string value = ddl_AuditEnvironment.SelectedValue;
String connectionString = ConfigurationManager.ConnectionStrings["stagingConnection"].ConnectionString;
// DataTable that stores the result set to be written on an excel.
DataTable dataTableObj = GetAuditData.GetDetailsTable(value, connectionString);
string attachment = "attachment; filename=Summary.xlsx";
DataTable dataTable = new DataTable();
XLWorkbook workbook = new XLWorkbook();
workbook.Worksheets.Add(dataTableObj, "Migrated Records");
using (MemoryStream memory = new MemoryStream())
{
Response.Clear();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", attachment);
workbook.SaveAs(memory);
memory.WriteTo(Response.OutputStream);
memory.Close();
Response.End();
}
}
The following code exports some data, downloading it in an XLS file.
What I want is to give all the three list and export each list of data in a separate sheet. How can I do that?
My code looks like this:
public bool ExportQuestionSet(int QuestionSetNo)
{
ExportResponse response = new ExportResponse();
QuestionSetTbl questionSetTbl = _questionSetDAO.GetQuestionSetByQuestionSetNo(QuestionSetNo);
QuestionSetContract questionSetContract = GetQuestionSetByQuestionSetNo(QuestionSetNo);
GridView gv = new GridView();
gv.DataSource = questionSetContract.QuestionsInfoList;
gv.DataBind();
Response.ClearContent();
Response.Buffer = true;
Response.AddHeader("content-disposition", "attachment; filename=QuestionSet.xls");
Response.ContentType = "application/ms-excel";
Response.Charset = "";
StringWriter sw = new StringWriter();
System.Web.UI.HtmlTextWriter htw = new System.Web.UI.HtmlTextWriter(sw);
gv.RenderControl(htw);
Response.Output.Write(sw.ToString());
Response.Flush();
Response.End();
return response.TaskComplete;
}
You can't output HTML and call it Excel. This works well for a reasonably formatted table, but it isn't an Excel file and will never be recognized as such. The file can be read, but it isn't possible to export multiple sheets.
Use a library to create a proper Excel file.
I would suggest using OpenXml, as it's quite fast and will create the correct Excel file. Using the sample in this thread: https://stackoverflow.com/a/11812551/1361993 you can just create a dataset with multiple datatables, which will in turn be outputted to the respective sheets in the file.
I have this method of creating an Excel spreedsheet with my data listed below.
List<ReportData> rd = ReportData.getReportData(startTime, endTime, lNumber, sNumber);
DataTable dt = buildDataTable(rd);
//we actually ahve to have a gridview to put into excel
GridView gv = new GridView();
gv.DataSource = dt;
gv.DataBind();
//flush everything from response to be sure we get a clean start
Response.ClearContent();
//now we create excel file
Response.AddHeader("content-disposition", "attachment;filename=UserRpt.xls");
Response.ContentType = "application/vnd.ms-excel";
Response.Charset = "";
StringWriter sw = new StringWriter();
HtmlTextWriter tw = new HtmlTextWriter(sw);
gv.RenderControl(tw);
//send xls as response
Response.Write(sw.ToString());
Response.End();
My question is how can make it create more pages and write the data to them without creating multiple reports for each individual thing? Example: Page one display the first gv, second page display the second gv and so on. When I add a new grid it does not create a new page it just puts everything back to back. I hope this makes sense I will be happy to try to clarify anything. Thank you for your help!
There are lots of libraries that will help you with this. Some require Office to be installed, others don't.
Maybe try
http://www.nuget.org/packages/ExcelGenerator
or
http://closedxml.codeplex.com/
I am working as Social Media Developer at Aspose and our Aspose.Cells API can be used to implement your requirement with ease. Please see the following sample code in this regard which exports the data from 3 different gridviews to three different excel sheets:
//Create a new Workbook
Aspose.Cells.Workbook workbook = new Aspose.Cells.Workbook();
//Add 2 more worksheets other than default worksheet
for (int i = 1; i <= 2; i++)
{
//Add a new worksheet
workbook.Worksheets.Add();
}
//Import data from gridviews to worksheets
workbook.Worksheets[0].Cells.ImportGridView(Gridview1, 0, 0, true, false, true);
workbook.Worksheets[1].Cells.ImportGridView(Gridview2, 0, 0, true, false, true);
workbook.Worksheets[2].Cells.ImportGridView(Gridview3, 0, 0, true, false, true);
//Save the worksheet
workbook.Save("C:\\Data\\Aspose.xls");
i have been trying export grid view to doc . and facing issues .
List of data contains data from database in from of List<>.
GridView GridView1 = new GridView();
GridView1.AllowPaging = false;
GridView1.DataSource = ListofData;
GridView1.DataBind();
Response.ClearContent();
Response.Buffer = true;
Response.AddHeader("content-disposition", "attachment; filename=Export-Grid.doc");
Response.Charset = "";
Response.ContentType = "application/vnd.word";
StringWriter sw = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
GridView1.RenderControl(htw);
Response.Write(sw.ToString());
Response.Flush();
Response.End();
problem with this approach is
1) when i open Export-Grid.doc in Office 2013 it prompts me that u want to open file as HTml Document , PDF document etc . if i try to open document using HTML it writes all data in file but in html form and if i use Plain text option it do same thing writes html data.
2) if i try to open Export-Grid.doc using open office it open the document but columns width is to big
i m using asp.net mvc. can some one help me how can i fix this or let me know wat m doing wrong ???
any help will be appreciated