This question already has answers here:
Download Excel file via AJAX MVC
(15 answers)
How to download excel using ajax call?
(1 answer)
Closed 2 years ago.
I have a list of items from the database base that I will like to generate in excel and PDF. I want to do the excel first. I have not done this before, following a tutorial online I was able to get it to return FIle. But the problem is that I got "non invocable member 'File" cannot be used like a method". I have already used "using System.IO;"
Can someone help figure out what I am doing wrong
{
try
{
//var parameters = new { UserName = username, Password = password };
//var sql = "select * from users where username = #UserName and password = #Password";
//var result = connection.Query(sql, parameters);
IEnumerable<DailyInterest> dailyInterests = null;
var Id = id;
using (var conn = new SqlConnection(connectionstring))
{
await conn.OpenAsync();
//var parameters = new { Id = id };
dailyInterests = conn.Query<DailyInterest>("Select * from DailyInterest where LoanAccountNo=#Id", new { Id = id });
//step1: create array to holder header labels
string[] col_names = new string[]{
"Loan Account No",
"Transaction Amount",
"Interest Rate",
"Interest Amount",
"Original Loan Amount",
"Narration",
"DRCR",
"Transaction Date"
};
//step2: create result byte array
byte[] result;
//step3: create a new package using memory safe structure
using (var package = new ExcelPackage())
{
//step4: create a new worksheet
var worksheet = package.Workbook.Worksheets.Add("final");
//step5: fill in header row
//worksheet.Cells[row,col]. {Style, Value}
for (int i = 0; i < col_names.Length; i++)
{
worksheet.Cells[1, i + 1].Style.Font.Size = 14; //font
worksheet.Cells[1, i + 1].Value = col_names[i]; //value
worksheet.Cells[1, i + 1].Style.Font.Bold = true; //bold
//border the cell
worksheet.Cells[1, i + 1].Style.Border.BorderAround(OfficeOpenXml.Style.ExcelBorderStyle.Thin);
//set background color for each sell
worksheet.Cells[1, i + 1].Style.Fill.PatternType = ExcelFillStyle.Solid;
worksheet.Cells[1, i + 1].Style.Fill.BackgroundColor.SetColor(Color.FromArgb(255, 243, 214));
}
int row = 8;
//step6: loop through query result and fill in cells
foreach (var item in dailyInterests)
{
for (int col = 1; col <= 2; col++)
{
worksheet.Cells[row, col].Style.Font.Size = 12;
//worksheet.Cells[row, col].Style.Font.Bold = true;
worksheet.Cells[row, col].Style.Border.BorderAround(OfficeOpenXml.Style.ExcelBorderStyle.Thin);
}
//set row,column data
worksheet.Cells[row, 1].Value = item.LoanAccountNo;
worksheet.Cells[row, 2].Value = item.TranAmount;
worksheet.Cells[row, 3].Value = item.InterestRatePerDay;
worksheet.Cells[row, 4].Value = item.AmountPerDay;
worksheet.Cells[row, 5].Value = item.OriginalLoanAmount;
worksheet.Cells[row, 6].Value = item.Narration;
worksheet.Cells[row, 7].Value = item.DRCR;
worksheet.Cells[row, 8].Value = item.TranDate;
//toggle background color
//even row with ribbon style
if (row % 8 == 0)
{
worksheet.Cells[row, 1].Style.Fill.PatternType = ExcelFillStyle.Solid;
worksheet.Cells[row, 1].Style.Fill.BackgroundColor.SetColor(Color.FromArgb(154, 211, 157));
worksheet.Cells[row, 2].Style.Fill.PatternType = ExcelFillStyle.Solid;
worksheet.Cells[row, 2].Style.Fill.BackgroundColor.SetColor(Color.FromArgb(154, 211, 157));
}
row++;
}
//step7: auto fit columns
worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns();
//step8: convert the package as byte array
result = package.GetAsByteArray();
}
//step9: return byte array as a file
**//This is where the error is**
return File(result, "application/vnd.ms-excel", "test.xls");
}
}
catch (Exception ex)
{
throw ex;
}
}
Related
First of all I know there are some answers to this error messsage, but nothing has helped, whether it is the removal of 0 indexing etc.
The part where I export the data from my SQL query to the DataTable is working and the data in my DataTable is correct, so that's not the problem.
The first part is my Excel and is where I check if there is an existing file or not and create a new file with the data. newsletter is my DataTable - I know its not a good name:
string path2 = "C:\\Users\\pandev\\newsletter.xls";
if (File.Exists(path2) == true)
{
Process[] pp = Process.GetProcessesByName("excel");
foreach (Process p in pp)
{
if (p.MainWindowTitle.Length == 0)
p.Kill();
}
File.Delete(path2);
}
using (FileStream sw = File.Create(path + "newsletter" + ".xls"))
{
var data = Encoding.Unicode.GetBytes("Artikelnummer" + "\t" + "Hersteller" + "\t" + "Beschreibung" + "\t" + "Nettopreis" + "\t" + "Bruttopreis" + "\t" + "Zustand" + "\t" + "P/N" + "\t" + "Kategorie I" + "\t" + "Kategorie II" + "\t" + "Kategorie III" + "\t" + "Shop-Link" + "\n");
sw.Write(data, 0, data.Length);
foreach (DataRow r in newsletter.Rows)
{
data = Encoding.Unicode.GetBytes(r["Artikelnummer"].ToString() + "\t" + r["Hersteller"].ToString() + "\t" + r["Bezeichnung"].ToString() + "\t" + r["Nettopreis"].ToString() + "\t" + r["Bruttopreis"].ToString() + "\t" + r["Zustand"].ToString() + "\t" + r["PN"].ToString() + "\t" + r["Kategorie I"].ToString() + "\t" + r["Kategorie II"].ToString() + "\t" + r["Kategorie III"].ToString() + "\t" + r["Link"].ToString() + "\n");
sw.Write(data, 0, data.Length);
}
}
Then I have this following code to make some Style changes in the Excel sheet:
Microsoft.Office.Interop.Excel.Application oXL = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook oWB = oXL.Workbooks.Open(path + "newsletter.xls");
Microsoft.Office.Interop.Excel.Worksheet oWS = oWB.Worksheets[1] as Microsoft.Office.Interop.Excel.Worksheet;
Microsoft.Office.Interop.Excel.Range exrngKopf = (Microsoft.Office.Interop.Excel.Range)oWS.Rows[1].Cells[1, oWS.Columns.Count];
Microsoft.Office.Interop.Excel.Range allBZ = oWS.UsedRange;
allBZ.EntireColumn.AutoFit();
error += "T";
oXL.DisplayAlerts = false;
error += "T";
oWS.Name = "GEKKO Computer GmbH";
error += "T";
oWS.Cells.Borders.LineStyle = Microsoft.Office.Interop.Excel.XlLineStyle.xlLineStyleNone;
error += "T";
exrngKopf.EntireRow.Font.Bold = true;
error += "T";
oWB.Activate();
error += "T";
oWB.Application.ActiveWindow.SplitRow = 1;
error += "T";
oWB.Application.ActiveWindow.FreezePanes = true;
error += "T";
Microsoft.Office.Interop.Excel.Range Firstrow = (Microsoft.Office.Interop.Excel.Range)oWS.Rows[1];
error += "T";
error += "x";
if (oWS.AutoFilter != null)
oWS.AutoFilterMode = false;
oWS.ListObjects.AddEx(Microsoft.Office.Interop.Excel.XlListObjectSourceType.xlSrcRange, allBZ, Type.Missing, Microsoft.Office.Interop.Excel.XlYesNoGuess.xlYes, Type.Missing).Name = "WFTableStyle";
oWS.ListObjects.get_Item("WFTableStyle").TableStyle = null;
oWB.SaveAs(path + "newsletter.xls", Microsoft.Office.Interop.Excel.XlFileFormat.xlWorkbookNormal, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value);
oWB.Close(true, Missing.Value, Missing.Value);
oXL.Quit();
So normally thats working, but now I have the special case where there is a Hyperlink in the data:
How I want the Hyperlink to look in the Excel cell is:
And like this in the edit field of that cell:
To fix the hyperlink I've placed the following code within the previous code snippet - before the SaveAs Close and Quit part:
for (int i = 0; i < newsletter.Rows.Count; i++)
{
for (int j = 0; j < newsletter.Columns.Count; j++)
{
oWS.Cells[i + 1, j + 1] = newsletter.Rows[i][j].ToString();
}
}
It's working. Every time I execute that code it saves the data correct in the Excel sheet, but the following exception occurs HRESULT: 0x800A03EC.
Does anyone have an idea on how to fix that?
I also tried something like this but still receive the same error:
for (int Idx = 1; Idx < newsletter.Columns.Count; Idx++)
{
oWS.Range["A1"].Offset[0, Idx].Value = newsletter.Columns[Idx].ColumnName;
}
for (int Idx = 1; Idx < newsletter.Rows.Count; Idx++)
{ // <small>hey! I did not invent this line of code,
// I found it somewhere on CodeProject.</small>
// <small>It works to add the whole row at once, pretty cool huh?</small>
oWS.Range["A2"].Offset[Idx].Resize[1, newsletter.Columns.Count].Value =
newsletter.Rows[Idx].ItemArray;
}
Given the following definition for DataTable (name: dataTableNewsLetter):
DataTable dataTableNewsletter = new DataTable();
//add columns
//dataTableNewsletter.Columns.Add(new DataColumn() { Caption = "Artikelnummer", ColumnName = "Artikelnummer", DataType = System.Type.GetType("System.String") });
dataTableNewsletter.Columns.Add(new DataColumn() { ColumnName = "Artikelnummer", DataType = System.Type.GetType("System.String") });
dataTableNewsletter.Columns.Add(new DataColumn() { ColumnName = "Hersteller", DataType = System.Type.GetType("System.String") });
dataTableNewsletter.Columns.Add(new DataColumn() { ColumnName = "Beschreibung", DataType = System.Type.GetType("System.String") });
dataTableNewsletter.Columns.Add(new DataColumn() { ColumnName = "Nettopreis", DataType = System.Type.GetType("System.Decimal") });
dataTableNewsletter.Columns.Add(new DataColumn() { ColumnName = "Bruttopreis", DataType = System.Type.GetType("System.Decimal") });
dataTableNewsletter.Columns.Add(new DataColumn() { ColumnName = "Zustand", DataType = System.Type.GetType("System.String") });
dataTableNewsletter.Columns.Add(new DataColumn() { ColumnName = "P/N", DataType = System.Type.GetType("System.String") });
dataTableNewsletter.Columns.Add(new DataColumn() { ColumnName = "Kategorie I", DataType = System.Type.GetType("System.String") });
dataTableNewsletter.Columns.Add(new DataColumn() { ColumnName = "Kategorie II", DataType = System.Type.GetType("System.String") });
dataTableNewsletter.Columns.Add(new DataColumn() { ColumnName = "Kategorie III", DataType = System.Type.GetType("System.String") });
dataTableNewsletter.Columns.Add(new DataColumn() { ColumnName = "Shop-Link", DataType = System.Type.GetType("System.String") });
//add data
DataRow row = dataTableNewsletter.NewRow();
row["Artikelnummer"] = "50018113"; //item number
row["Hersteller"] = "HP"; //manufacturer
row["Beschreibung"] = "HP DL38X Gen10 2 Drive NVMe Slim SAS Cable Kit - 871827-B21 NEU"; //description
row["Nettopreis"] = 195; //net price
row["Bruttopreis"] = 195; //gross price
row["Zustand"] = "New"; //condition
row["P/N"] = "869812-001"; //part number
row["Kategorie I"] = "Komponenten"; //category 1
row["Kategorie II"] = "Kabel-Adapter"; //category 2
row["Kategorie III"] = "NVMe-Kabel"; //category 3
row["Shop-Link"] = "https://www.gekko-computer.de/Komponenten/Kabel-Adapter/NVMe-Kabel/HP-DL38X-Gen10-2-Drive-NVMe-Slim-SAS-Cable-Kit-871827-B21-NEU.html"; //URL
//add
dataTableNewsletter.Rows.Add(row);
//add new row
row = dataTableNewsletter.NewRow();
row["Artikelnummer"] = "50015171"; //item number
row["Hersteller"] = ""; //manufacturer
row["Beschreibung"] = "NetApp Ethernet Kabel CAT 6 2m - 112-00195 X6561-R6"; //description
row["Nettopreis"] = 38; //net price
row["Bruttopreis"] = 38; //gross price
row["Zustand"] = "Used"; //condition
row["P/N"] = "112-00195"; //part number
row["Kategorie I"] = "sonstiges"; //category 1
row["Kategorie II"] = "Kabel-Adapter"; //category 2
row["Kategorie III"] = "Ethernet-Kabel"; //category 3
row["Shop-Link"] = "https://www.gekko-computer.de/sonstiges/Kabel-Adapter/Ethernet-Kabel/NetApp-Ethernet-Kabel-CAT-6-2m-112-00195-X6561-R6.html"; //URL
//add
dataTableNewsletter.Rows.Add(row);
The exception: Exception from HRESULT: 0x800A03EC can be replicated by doing the following:
for (int i = 0; i < dataTableNewsletter.Rows.Count; i++)
{
//first row contains headers
int xlRowNum = i + 2;
string description = dataTableNewsletter.Rows[i]["Beschreibung"].ToString();
string url = dataTableNewsletter.Rows[i]["Shop-Link"].ToString();
//create hyperlink
Debug.WriteLine($"location: {i}, 11");
//The next line results in 'Exception from HRESULT: 0x800A03EC'
//because 0 is an invalid index in Excel
((Excel.Range)xlWSheet.Cells[i, 11]).Formula = $"=HYPERLINK(\"{url}\", \"{description}\")";
}
It looks like you are creating a .xls (older Excel) file instead of a .xlsx (newer Excel) file. If you create a .xlsx file you could use one of the following NuGet packages instead of Excel Interop:
DocumentFormat.OpenXml
ClosedXml
EPPlus
NPOI
Is the tab-delimited file something you just created for testing?
A tab-delimited file isn't really an Excel file. If you open Excel and select File => Save As, you'll see that a tab-delimited file is saved as a .txt file. When I opened the tab-delimited file in Excel it generated a warning about the file format not matching the file extension. If the tab-delimited file is saved with a .txt extension, Excel seems to open a wizard when the file is opened. This can be eliminated by naming the file with a .csv extension instead - although it's not really a .csv file either, but it doesn't seem to generate any warnings.
Since you're retrieving data from a database and stated that the data is already in a DataTable, it seems prudent to use the DataTable to create the Excel workbook.
Try the following (Excel Interop):
Create a new Windows Forms App (.NET Framework) project.
Then either download / install NuGet package: Microsoft.Office.Interop.Excel or add a reference to Microsoft Excel xx.x Object Library (Project => Add Reference...=> COM => Microsoft Excel xx.x Object Library (ex: Microsoft Excel 16.0 Object Library))
Add the following using directives:
using Excel = Microsoft.Office.Interop.Excel;
using System.IO;
using System.Data;
using System.Diagnostics;
CreateExcelWorkbook:
public static void CreateExcelWorkbook(DataTable dataTableNewsletter, string excelFilename)
{
Excel.Application xlApp = null;
Excel.Workbook xlWBook = null;
Excel.Worksheet xlWSheet = null;
Excel.Range allBZ = null;
Excel.Range exrngKopf = null;
try
{
if (dataTableNewsletter == null)
throw new Exception("Error - Data table is null.");
else if (dataTableNewsletter.Rows.Count <= 0)
throw new Exception($"Error - Data table doesn't contain any data.");
//create new instance
xlApp = new Excel.Application();
//whether or not to make Excel visible
xlApp.Visible = true;
//prevent prompting to overwrite existing file
xlApp.DisplayAlerts = false;
//disable user control while modifying the Excel Workbook
//to prevent user interference
//only necessary if Excel application Visibility property = true
//need to re-enable before exiting this method
//xlApp.UserControl = false;
//if writing/updating a large amount of data
//disable screen updating by setting value to false
//for better performance.
//re-enable when done writing/updating data, if desired
//excelApp.ScreenUpdating = false;
//add Workbook
xlWBook = xlApp.Workbooks.Add();
//activate
xlWBook.Activate();
if (xlWBook.Worksheets.Count > 0)
xlWSheet = (Excel.Worksheet)xlWBook.ActiveSheet;
else
xlWSheet = (Excel.Worksheet)xlWBook.Sheets.Add();
xlWSheet.Name = "GEKKO Computer GmbH";
//write column headers
//Excel indices start with 1; A1 = 1,1
for (int j = 0; j < dataTableNewsletter.Columns.Count; j++)
{
int xlColNum = j + 1;
//set value - column header
xlWSheet.Cells[1, xlColNum] = dataTableNewsletter.Columns[j].ColumnName;
//get range for column
//Excel.Range colRng = ((Excel.Range)xlWSheet.Cells[1, xlColNum]).EntireColumn;
//use DataTable data types to set data type for Excel column
//ToDo: change as desired
if (dataTableNewsletter.Columns[j].DataType.ToString() == "System.DateTime")
((Excel.Range)xlWSheet.Cells[1, xlColNum]).EntireColumn.NumberFormat = #"yyyy\-mm\-dd;#";
else if (dataTableNewsletter.Columns[j].DataType.ToString() == "System.Int32")
((Excel.Range)xlWSheet.Cells[1, xlColNum]).EntireColumn.NumberFormat = 0;
else if (dataTableNewsletter.Columns[j].DataType.ToString() == "System.Decimal")
((Excel.Range)xlWSheet.Cells[1, xlColNum]).EntireColumn.NumberFormat = "0.00";
}
//set values in Excel using data from DataTable
//ToDo: add desired code
for (int i = 0; i < dataTableNewsletter.Rows.Count; i++)
{
//Excel row numbers start with 1
//headers are in row 1, so data starts in row 2
int xlRowNum = i + 2;
for (int j = 0; j < dataTableNewsletter.Columns.Count; j++)
{
//Excel column numbers start with 1
int xlColNum = j + 1;
if (dataTableNewsletter.Rows[i][dataTableNewsletter.Columns[j].ColumnName] != null && dataTableNewsletter.Rows[i][dataTableNewsletter.Columns[j].ColumnName] != DBNull.Value)
{
//set cell value
xlWSheet.Cells[xlRowNum, xlColNum] = dataTableNewsletter.Rows[i][dataTableNewsletter.Columns[j].ColumnName].ToString();
}
}
}
//set value
allBZ = (Excel.Range)xlWSheet.UsedRange;
//Debug.WriteLine($"allBZ.Rows.Count: {allBZ.Rows.Count}; allBZ.Columns.Count: {allBZ.Columns.Count}");
//auto fit
allBZ.EntireColumn.AutoFit();
//set value
//exrngKopf = (Excel.Range)xlWSheet.Rows[1]; //row 1; header row
exrngKopf = (Excel.Range)xlWSheet.Cells[1, allBZ.Columns.Count]; //row 1; header row
exrngKopf.EntireRow.Font.Bold = true;
//set Border line style
xlWSheet.Cells.Borders.LineStyle = Excel.XlLineStyle.xlLineStyleNone;
xlWBook.Application.ActiveWindow.SplitRow = 1;
xlWBook.Application.ActiveWindow.FreezePanes = true;
if (xlWSheet.AutoFilter != null)
xlWSheet.AutoFilterMode = false;
xlWSheet.ListObjects.AddEx(Excel.XlListObjectSourceType.xlSrcRange, allBZ, Type.Missing, Excel.XlYesNoGuess.xlYes, Type.Missing).Name = "WFTableStyle";
xlWSheet.ListObjects.get_Item("WFTableStyle").TableStyle = null;
//fix hyperlinks
for (int i = 0; i < dataTableNewsletter.Rows.Count; i++)
{
//first row contains headers
int xlRowNum = i + 2;
//string description = dataTableNewsletter.Rows[i]["Beschreibung"].ToString();
string description = dataTableNewsletter.Rows[i]["Beschreibung"].ToString() + " - " + DateTime.Now.ToString("HH:mm:ss.fff");
string url = dataTableNewsletter.Rows[i]["Shop-Link"].ToString();
Debug.WriteLine($"Description: {description}; URL[{xlRowNum}, 11]: '{url}'");
//create hyperlink - option 1
//xlWSheet.Hyperlinks.Add(xlWSheet.Cells[xlRowNum, 11], url, System.Reflection.Missing.Value, description, description);
//create hyperlink - option 2
((Excel.Range)xlWSheet.Cells[xlRowNum, 11]).Formula = $"=HYPERLINK(\"{url}\", \"{description}\")"; //works
//Debug.WriteLine($"location: {i}, 11");
//((Excel.Range)xlWSheet.Cells[i, 11]).Formula = $"=HYPERLINK(\"{url}\", \"{description}\")"; //Exception from HRESULT: 0x800A03EC
}
//save Workbook - if file exists, overwrite it
//xlWBook.SaveAs(filename, Excel.XlFileFormat.xlWorkbookDefault, System.Reflection.Missing.Value, System.Reflection.Missing.Value, true, false, Excel.XlSaveAsAccessMode.xlNoChange, Excel.XlSaveConflictResolution.xlLocalSessionChanges, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value);
xlWBook.SaveAs(excelFilename, Excel.XlFileFormat.xlWorkbookNormal, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, Excel.XlSaveAsAccessMode.xlNoChange, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value);
}
finally
{
if (xlWBook != null)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(allBZ);
System.Runtime.InteropServices.Marshal.ReleaseComObject(exrngKopf);
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWSheet);
xlWSheet = null;
allBZ = null;
exrngKopf = null;
//close Workbook
xlWBook.Close(false);
//release all resources
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWBook);
xlWBook = null;
}
System.Threading.Thread.Sleep(150);
if (xlApp != null)
{
//quit
xlApp.Quit();
//release all resources
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(xlApp);
xlApp = null;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
System.Threading.Thread.Sleep(175);
}
}
}
Usage:
string excelFilename = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "newsletter.xls");
HelperExcel.CreateExcelWorkbook(dataTableNewsletter, excelFilename);
//the following is necessary otherwise the Excel process seems to persist in Task Manager
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
Resources:
Microsoft.Office.Interop.Excel Namespace
Range.EntireColumn Property
How do I get an Excel range using row and column numbers in VSTO / C#?
C# Excel how to add hyperlink with cell link
How To Create A Hyperlink Using Excel Hyperlink() Function In EPPlus .NET Application (C#) Part - Seven
How to automate Microsoft Excel from Microsoft Visual C#.NET
How to automate Excel by using Visual C# to fill or to obtain data in a range by using arrays
How to sort a PivotTable with Interop.Excel and C#?
I got the generation of the PivotTable fully like I want it to, but struggling with the sorting...
Sorting should be done, that for "Title" and "SubTitle" the fields "Value2" are always having the highest descending values at the top per project.
Was trying around via Range.Sort() but without luck.
Tested way:
Defining a region (like I did manually in Excel for figuring out the way) with "C4" and the doing a Range.Sort on this. But then it is working for the first project, but not for all. Imho, because I set this only to the pointed range to one cell. The next try was to extend the range, but then I always got HRESULT exceptions with just an memory address given (useless for me).
The screenshots are showing the wanted sorting.
public void GeneratePivot()
{
const string numberFormat = "#,##0 €;-#,##0 €";
var missing = Type.Missing;
string dataContext = #"DataContext";
#region // Create Data
var dt = new DataTable();
dt.Columns.Add(new DataColumn() { ColumnName = "Project", DataType = typeof(string) });
dt.Columns.Add(new DataColumn() { ColumnName = "Title", DataType = typeof(string) });
dt.Columns.Add(new DataColumn() { ColumnName = "SubTitle", DataType = typeof(string) });
dt.Columns.Add(new DataColumn() { ColumnName = "Value1", DataType = typeof(decimal) });
dt.Columns.Add(new DataColumn() { ColumnName = "Value2", DataType = typeof(decimal) });
var row1 = dt.NewRow();
row1["Project"] = "Project1";
row1["Title"] = "Title1";
row1["SubTitle"] = "SubTitle1-1";
row1["Value1"] = 1000M;
row1["Value2"] = 40000M;
dt.Rows.Add(row1);
var row2 = dt.NewRow();
row2["Project"] = "Project2-1";
row2["Title"] = "Title2";
row2["SubTitle"] = "SubTitle2-1";
row2["Value1"] = 100M;
row2["Value2"] = 4000M;
dt.Rows.Add(row2);
var row3 = dt.NewRow();
row3["Project"] = "Project2-2";
row3["Title"] = "Title2";
row3["SubTitle"] = "SubTitle2-2";
row3["Value1"] = 220M;
row3["Value2"] = 222000M;
dt.Rows.Add(row3);
var row4 = dt.NewRow();
row4["Project"] = "Project3-1";
row4["Title"] = "Title3";
row4["SubTitle"] = "SubTitle3-1";
row4["Value1"] = 32423M;
row4["Value2"] = 430M;
dt.Rows.Add(row4);
var row5 = dt.NewRow();
row5["Project"] = "Project3-2";
row5["Title"] = "Title3";
row5["SubTitle"] = "SubTitle3-2";
row5["Value1"] = 2341M;
row5["Value2"] = 4002000M;
dt.Rows.Add(row5);
#endregion
// Create Workbook with Excel Interop
Excel.Application excelApplication = new Excel.Application();
Excel.Workbooks workbooks = excelApplication.Workbooks;
var workbook = workbooks.Add();
#region // Create DataSheet
Excel.Worksheet worksheet1 = workbook.Sheets[1];
worksheet1.Name = "DataSheet";
var colsCount = dt.Columns.Count;
var rowsCount = dt.Rows.Count;
Excel.Range range;
// Create DataArray from DataTable
object[,] dtArray = new object[rowsCount, colsCount];
for (int i = 0; i < rowsCount; i++)
{
for (int j = 0; j < colsCount; j++) { dtArray[i, j] = dt.Rows[i][j]; }
}
// Create header
range = worksheet1.Cells[1, 1];
range = range.get_Resize(1, colsCount);
range.NumberFormat = "#";
range.Font.Bold = true;
range.Value = new string[5] { "Project", "Title", "SubTitle", "Value1", "Value2" };
// Get an Excel Range of the same dimensions
range = (Excel.Range)worksheet1.Cells[2, 1];
range = range.get_Resize(rowsCount, colsCount);
// Assign the 2-d array to the Excel Range
range.set_Value(Excel.XlRangeValueDataType.xlRangeValueDefault, dtArray);
range = worksheet1.UsedRange;
worksheet1.Names.Add("DataContext", range);
#endregion
#region // Create PivotSheet
Excel.Worksheet worksheet2 = workbook.Sheets.Add(After: workbook.Sheets[workbook.Sheets.Count]);
worksheet2.Name = "PivotSheet";
Excel.PivotCache pivotCache;
Excel.PivotTable pivotTable;
Excel.Range pivotData;
Excel.Range pivotDestination;
// Select a range of data for the Pivot Table.
pivotData = worksheet1.get_Range(dataContext);
// Select location of the Pivot Table.
pivotDestination = worksheet2.get_Range("A1", missing);
// create Pivot Cache and Pivot Table
pivotCache = (Excel.PivotCache)workbook.PivotCaches()
.Add(Excel.XlPivotTableSourceType.xlDatabase, pivotData);
pivotTable = (Excel.PivotTable)worksheet2.PivotTables()
.Add(PivotCache: pivotCache, TableDestination: pivotDestination, TableName: dataContext);
// Style Pivot Table
pivotTable.Format(Excel.XlPivotFormatType.xlReport2);
pivotTable.InGridDropZones = false;
pivotTable.SmallGrid = false;
pivotTable.TableStyle2 = "PivotStyleLight16";
// ROW FIELDS
Excel.PivotField rowField3 = (Excel.PivotField)pivotTable.PivotFields("SubTitle");
rowField3.Orientation = Excel.XlPivotFieldOrientation.xlRowField;
rowField3.LayoutForm = Excel.XlLayoutFormType.xlOutline;
rowField3.LayoutSubtotalLocation = Excel.XlSubtototalLocationType.xlAtTop;
rowField3.LayoutCompactRow = true;
Excel.PivotField rowField2 = (Excel.PivotField)pivotTable.PivotFields("Title");
rowField2.Orientation = Excel.XlPivotFieldOrientation.xlRowField;
rowField2.LayoutForm = Excel.XlLayoutFormType.xlOutline;
rowField2.LayoutSubtotalLocation = Excel.XlSubtototalLocationType.xlAtTop;
rowField2.LayoutCompactRow = true;
Excel.PivotField rowField1 = (Excel.PivotField)pivotTable.PivotFields("Project");
rowField1.Orientation = Excel.XlPivotFieldOrientation.xlRowField;
rowField1.LayoutForm = Excel.XlLayoutFormType.xlOutline;
rowField1.LayoutSubtotalLocation = Excel.XlSubtototalLocationType.xlAtTop;
rowField1.LayoutCompactRow = true;
// FILTER FIELDS
Excel.PivotField pageField1 = (Excel.PivotField)pivotTable.PivotFields("Project");
pageField1.Orientation = Excel.XlPivotFieldOrientation.xlPageField;
pageField1.EnableMultiplePageItems = true;
// DATA FIELDS
int position = 1;
Excel.PivotField dataField1 = (Excel.PivotField)pivotTable.PivotFields("Value1");
dataField1.Orientation = Excel.XlPivotFieldOrientation.xlDataField;
dataField1.Function = Excel.XlConsolidationFunction.xlSum;
dataField1.NumberFormat = numberFormat;
dataField1.Position = position++;
Excel.PivotField dataField2 = (Excel.PivotField)pivotTable.PivotFields("Value2");
dataField2.Orientation = Excel.XlPivotFieldOrientation.xlDataField;
dataField2.Function = Excel.XlConsolidationFunction.xlSum;
dataField2.NumberFormat = numberFormat;
dataField2.Position = position++;
#endregion
// Close Excel
workbook.SaveAs("Interop.Excel_Pivot.xlsx");
workbook.Close();
excelApplication.Quit();
}
This did it!
var pivotLine = (Excel.PivotLine)pivotTable.PivotColumnAxis.PivotLines[2];
rowField2.AutoSortEx((int)Excel.XlSortOrder.xlDescending, "Summe von Value2", pivotLine, 1);
rowField3.AutoSortEx((int)Excel.XlSortOrder.xlDescending, "Summe von Value2", pivotLine, 1);
Hint: Beware of, that given String "Summe von " is german language and will be "Sum of " with Excel in English. ;)
I identified the code slowing down the process as this one (where I'm filling the cells):
What I'm doing here is basically loading some data from a database using a DataSet.
Microsoft.Office.Interop.Excel.Range range1 = null;
Microsoft.Office.Interop.Excel.Range cell1 = null;
Microsoft.Office.Interop.Excel.Borders border1 = null;
for (i = 0; i <= ds.Tables[0].Rows.Count - 1; i++)
{
int s = i + 1;
for (j = 0; j <= ds.Tables[0].Columns.Count - 1; j++)
{
data = ds.Tables[0].Rows[i].ItemArray[j].ToString();
xlWorkSheet.Cells[s + 1, j + 1] = data;
range1 = xlWorkSheet.UsedRange;
cell1 = range1.Cells[s + 1, j + 1];
border1 = cell1.Borders;
if (((IList)terms).Contains(xlWorkSheet.Cells[1, j + 1].Value.ToString()))
{
cell1.Interior.Color = System.Drawing.Color.Red;
}
range1.Columns.AutoFit();
range1.HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignCenter;
border1.LineStyle = Microsoft.Office.Interop.Excel.XlLineStyle.xlContinuous;
border1.Weight = 2d;
}
}
It's sometimes taking like more than 1 minute to load the whole thing. Is there is away to optimize it?.
Cell-by-cell is the slowest possible way to interact with Excel using Interop - look up how to add data to a sheet from an array in one operation.
E.g.
Write Array to Excel Range
shows this approach.
Interop libraries are extremely slow and spends huge source of system.
Instead of using Interop Libraries to create Excel files, you can simply use it OpenXML library.
I'm using it in production. And over 1 million rows it just takes about 10 seconds to export dataset to excel file.
Here is a sample code quoted from:
Export DataTable to Excel with Open Xml SDK in c#
private void ExportDSToExcel(DataSet ds, string destination)
{
using (var workbook = SpreadsheetDocument.Create(destination, DocumentFormat.OpenXml.SpreadsheetDocumentType.Workbook))
{
var workbookPart = workbook.AddWorkbookPart();
workbook.WorkbookPart.Workbook = new DocumentFormat.OpenXml.Spreadsheet.Workbook();
workbook.WorkbookPart.Workbook.Sheets = new DocumentFormat.OpenXml.Spreadsheet.Sheets();
uint sheetId = 1;
foreach (DataTable table in ds.Tables)
{
var sheetPart = workbook.WorkbookPart.AddNewPart<WorksheetPart>();
var sheetData = new DocumentFormat.OpenXml.Spreadsheet.SheetData();
sheetPart.Worksheet = new DocumentFormat.OpenXml.Spreadsheet.Worksheet(sheetData);
DocumentFormat.OpenXml.Spreadsheet.Sheets sheets = workbook.WorkbookPart.Workbook.GetFirstChild<DocumentFormat.OpenXml.Spreadsheet.Sheets>();
string relationshipId = workbook.WorkbookPart.GetIdOfPart(sheetPart);
if (sheets.Elements<DocumentFormat.OpenXml.Spreadsheet.Sheet>().Count() > 0)
{
sheetId =
sheets.Elements<DocumentFormat.OpenXml.Spreadsheet.Sheet>().Select(s => s.SheetId.Value).Max() + 1;
}
DocumentFormat.OpenXml.Spreadsheet.Sheet sheet = new DocumentFormat.OpenXml.Spreadsheet.Sheet() { Id = relationshipId, SheetId = sheetId, Name = table.TableName };
sheets.Append(sheet);
DocumentFormat.OpenXml.Spreadsheet.Row headerRow = new DocumentFormat.OpenXml.Spreadsheet.Row();
List<String> columns = new List<string>();
foreach (DataColumn column in table.Columns)
{
columns.Add(column.ColumnName);
DocumentFormat.OpenXml.Spreadsheet.Cell cell = new DocumentFormat.OpenXml.Spreadsheet.Cell();
cell.DataType = DocumentFormat.OpenXml.Spreadsheet.CellValues.String;
cell.CellValue = new DocumentFormat.OpenXml.Spreadsheet.CellValue(column.ColumnName);
headerRow.AppendChild(cell);
}
sheetData.AppendChild(headerRow);
foreach (DataRow dsrow in table.Rows)
{
DocumentFormat.OpenXml.Spreadsheet.Row newRow = new DocumentFormat.OpenXml.Spreadsheet.Row();
foreach (String col in columns)
{
DocumentFormat.OpenXml.Spreadsheet.Cell cell = new DocumentFormat.OpenXml.Spreadsheet.Cell();
cell.DataType = DocumentFormat.OpenXml.Spreadsheet.CellValues.String;
cell.CellValue = new DocumentFormat.OpenXml.Spreadsheet.CellValue(dsrow[col].ToString()); //
newRow.AppendChild(cell);
}
sheetData.AppendChild(newRow);
}
}
}
}
I have been stuck on this issue for a a day or so and need some help. In my application, I have some data in a listview, which is
public void OnHostPing(HostPinger host)
{
if (InvokeRequired)
{
Invoke(new OnPingDelegate(OnHostPing), new object[] { host });
return;
}
lock (_table)
{
ListViewItem item = (ListViewItem)_table[host.ID];
if (item != null)
{
item.SubItems[0].Text = host.HostIP.ToString();
item.SubItems[1].Text = host.HostName;
item.SubItems[2].Text = host.HostDescription;
item.SubItems[3].Text = host.StatusName;
item.SubItems[4].Text = host.SentPackets.ToString();
item.SubItems[5].Text = host.ReceivedPackets.ToString();
item.SubItems[6].Text = PercentToString(host.ReceivedPacketsPercent);
item.SubItems[7].Text = host.LostPackets.ToString();
item.SubItems[8].Text = PercentToString(host.LostPacketsPercent);
item.SubItems[9].Text = host.LastPacketLost ? "Yes" : "No";
item.SubItems[10].Text = host.ConsecutivePacketsLost.ToString();
item.SubItems[11].Text = host.MaxConsecutivePacketsLost.ToString();
item.SubItems[12].Text = host.RecentlyReceivedPackets.ToString();
item.SubItems[13].Text = PercentToString(host.RecentlyReceivedPacketsPercent);
item.SubItems[14].Text = host.RecentlyLostPackets.ToString();
item.SubItems[15].Text = PercentToString(host.RecentlyLostPacketsPercent);
item.SubItems[16].Text = host.CurrentResponseTime.ToString();
item.SubItems[17].Text = host.AverageResponseTime.ToString("F");
item.SubItems[18].Text = host.MinResponseTime.ToString();
item.SubItems[19].Text = host.MaxResponseTime.ToString();
item.SubItems[20].Text = DurationToString(host.CurrentStatusDuration);
item.SubItems[21].Text = DurationToString(host.GetStatusDuration(HostStatus.Alive));
item.SubItems[22].Text = DurationToString(host.GetStatusDuration(HostStatus.Dead));
item.SubItems[23].Text = DurationToString(host.GetStatusDuration(HostStatus.DnsError));
item.SubItems[24].Text = DurationToString(host.GetStatusDuration(HostStatus.Unknown));
item.SubItems[25].Text = PercentToString(host.HostAvailability);
item.SubItems[26].Text = DurationToString(host.TotalTestDuration);
item.SubItems[27].Text = DurationToString(host.CurrentTestDuration);
}
else
{
item = new ListViewItem(new string[]
{
host.HostIP.ToString(), host.HostName, host.HostDescription,
host.StatusName,
host.SentPackets.ToString(),
host.ReceivedPackets.ToString(), PercentToString(host.ReceivedPacketsPercent),
host.LostPackets.ToString(), PercentToString(host.LostPacketsPercent),
host.LastPacketLost ? "Yes" : "No",
host.ConsecutivePacketsLost.ToString(), host.MaxConsecutivePacketsLost.ToString(),
host.RecentlyReceivedPackets.ToString(), PercentToString(host.RecentlyReceivedPacketsPercent),
host.RecentlyLostPackets.ToString(), PercentToString(host.RecentlyLostPacketsPercent),
host.CurrentResponseTime.ToString(), host.AverageResponseTime.ToString("F"),
host.MinResponseTime.ToString(), host.MaxResponseTime.ToString(),
DurationToString(host.CurrentStatusDuration),
DurationToString(host.GetStatusDuration(HostStatus.Alive)),
DurationToString(host.GetStatusDuration(HostStatus.Dead)),
DurationToString(host.GetStatusDuration(HostStatus.DnsError)),
DurationToString(host.GetStatusDuration(HostStatus.Unknown)),
PercentToString(host.HostAvailability),
DurationToString(host.TotalTestDuration),
DurationToString(host.CurrentTestDuration)
});
What I can't seem to figure out is, how to get that data exported to Excel? I am able to export static data to Excel with this code
public static string RunSample1(DirectoryInfo outputDir)
{
if (!outputDir.Exists) throw new Exception("outputDir does not exist!");
FileInfo newFile = new FileInfo(outputDir.FullName + #"\sample1.xlsx");
if (newFile.Exists)
{
newFile.Delete(); // ensures we create a new workbook
newFile = new FileInfo(outputDir.FullName + #"\sample1.xlsx");
}
using (ExcelPackage package = new ExcelPackage(newFile))
{
// add a new worksheet to the empty workbook
ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("Current Devices");
//Add the headers
//worksheet.Cells[1, 1].Value = "ID";
worksheet.Cells[1, 1].Value = "";
worksheet.Cells[1, 2].Value = "Product";
worksheet.Cells[1, 3].Value = "Quantity";
worksheet.Cells[1, 4].Value = "Price";
worksheet.Cells[1, 5].Value = "Value";
//Add some items...
worksheet.Cells["A2"].Value = 12001;
worksheet.Cells["B2"].Value = "Nails";
worksheet.Cells["C2"].Value = 37;
worksheet.Cells["D2"].Value = 3.99;
What I can't figure out is how to get those listview items in to the spreadsheet cells instead of static data. ListViewItems doesn't seem to yield the properties I would expect. Can someone help me out a bit here?
I found a solution using Microsoft.Office.Interop.Excel instead of trying to use the EPPlus solution.
I have one Data table which is converting to the excel.for this i am using EPPlus dll. Here i am getting the generated excel file. but my problem is there are 2 columns are existing with rich text value. After Conversion the above column is always showing data with HTML tag. How I resolve this issue. Please help me. thanks in advance
My code is shown below
try
{
using (SPSite site = new SPSite(SPContext.Current.Web.Url))
{
using (SPWeb web = site.OpenWeb())
{
DataTable dtTemp = new DataTable();
if (ViewState["DTSource"] != null)
dtTemp = (DataTable)ViewState["DTSource"];
using (ExcelPackage pck = new ExcelPackage())
{
//Create the worksheet
ExcelWorksheet ws = pck.Workbook.Worksheets.Add("Sheet1");
//Load the datatable into the sheet, starting from cell A1. Print the column names on row 1
if (dtTemp != null && dtTemp.Rows.Count > 0)
{
ws.Cells["A1"].LoadFromDataTable(dtTemp, true);
using (ExcelRange rng = ws.Cells["A1:" + GetColumnName(dtTemp.Columns.Count) + "1"])
{
rng.Style.Font.Bold = true;
rng.Style.Fill.PatternType = ExcelFillStyle.Solid;
rng.Style.Fill.BackgroundColor.SetColor(Color.FromArgb(79, 129, 189));
rng.Style.Font.Color.SetColor(Color.White);
}
for (int i = 0; i < dtTemp.Columns.Count; i++)
{
if (dtTemp.Columns[i].DataType.FullName.Contains("DateTime"))
{
ws.Cells[2, i + 1, dtTemp.Rows.Count + 1, i + 1].Style.Numberformat.Format = "MM/dd/yyyy";
ws.Column(i + 1).Width = 15;
}
using (ExcelRange col = ws.Cells[2, 1, 2 + dtTemp.Rows.Count, 1])
{
col.Style.Numberformat.Format = "#,##0.00";
col.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
}
using (ExcelRange col = ws.Cells[2, 4, 2 + dtTemp.Rows.Count, 4])
{
col.IsRichText = true;
col.Style.HorizontalAlignment = ExcelHorizontalAlignment.Left;
}
Page.Response.Clear();
Page.Response.AddHeader("content-disposition", "attachment; filename=ExceptionTracker_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".xlsx");
Page.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Page.Response.BinaryWrite(pck.GetAsByteArray());
Page.Response.End();
}
}
else
{
string script = "window.frameElement.cancelPopUp(); return false;";
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "Close Window", script, true);
}
}
}
}
}
catch (Exception ex)
{
throw ex;
}
Shouldn't this part be somewhere else? Maybe after you have finished creating the file?
Page.Response.Clear();
Page.Response.AddHeader("content-disposition", "attachment; filename=ExceptionTracker_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".xlsx");
Page.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Page.Response.BinaryWrite(pck.GetAsByteArray());
Page.Response.End();