I have an input excel file which contains 6 columns and n number of rows. Out of which 3 columns are mandatory columns. If any of mandatory columns are empty then I need to update some custom text in the Remarks column. In the input excel column names are fixed but position is not fixed.
For example, in the below table I have updated Remarks column values of row no. 2 & 3 as Fail since CCode and ID column values are blank.
Name
ID
ComapanyName
CCode
Address
Remarks
Anto
12
ABC Corp Cmp
ABCCo
AvenueSt
Anuj
13
XYZ Corp Cmp
AvenueSt
Fail
Kathy
CTF Corp Cmp
CTFCo
AvenueSt
Fail
Close XML Logic:
var workbook = new XLWorkbook(IPPath);
var rows = workbook.Worksheet(1).RangeUsed().RowsUsed().Skip(1);
foreach (var row in rows)
{
-- update logic
}
First you need to read the excel data in DataTable, then you should be able to update the excel data by iterating each record.
private static System.Data.DataTable ReadExcelData(string filePath)
{
try
{
System.Data.DataTable dataTable = new System.Data.DataTable();
using (Stream stream = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
using (XLWorkbook workBook = new XLWorkbook(stream))
{
var workSheet = workBook.Worksheet(1);
dataTable.TableName = workSheet.Name;
int lastRowIndex = workSheet.LastRowUsed().RowNumber();
int lastColumnIndex = workSheet.LastColumnUsed().ColumnNumber();
bool header = false;
foreach (IXLRow row in workSheet.Rows(1, lastRowIndex))
{
if (!header)
{
foreach (IXLCell cell in row.Cells(1, lastColumnIndex))
{
dataTable.Columns.Add(cell.GetFormattedString());
}
header = true;
}
dataTable.Rows.Add();
int i = 0;
foreach (IXLCell cell in row.Cells(1, lastColumnIndex))
{
dataTable.Rows[dataTable.Rows.Count - 1][i] = cell.GetFormattedString();
i++;
}
}
dataTable.Rows.RemoveAt(0);
}
}
return dataTable;
}
catch (Exception ex)
{
return null;
}
}
public static void UpdateData(string filePath, DataTable dataTable)
{
using (Stream stream = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
using (XLWorkbook workBook = new XLWorkbook(stream))
{
var workSheet = workBook.Worksheet(1);
if (workSheet != null)
{
int ColumnIndex = 0;
int rowNumber = 1;
foreach (DataColumn column in dataTable.Columns)
{
if (column.ColumnName.Contains("Column Name"))
{
ColumnIndex = column.Ordinal + 1;
}
}
string colAddress = ColumnAddress(ColumnIndex);
foreach (DataRow row in dataTable.Rows)
{
rowNumber++;
workSheet.Cell(rowNumber, ColumnIndex).Value = "Update Value";
}
}
workBook.Save();
}
}
}
private static string ColumnAddress(int col)
{
if (col <= 26)
{
return Convert.ToString(Convert.ToChar(col + 64));
}
int div = col / 26;
int mod = col % 26;
if (mod == 0) { mod = 26; div--; }
return ColumnAddress(div) + ColumnAddress(mod);
}
I create a pivot table based on an Excel (.xlsx) file. The program adds fields to rows, values, and the filter. Using PivotFilters.Add2 causes 0x800a03ec error which terminates the program. How to properly use PivotFilters.Add2?
I tried filtering on different fields with different data types. Also, I tried using Type.Missing in a place of unused arguments. There seems to be plenty of information of this method for VB, but not so much for C#.
Items selected in the filter should be between the two dates on the last line.
var xlApp = new Microsoft.Office.Interop.Excel.Application();
xlApp.Visible = true;
var workBook = xlApp.Workbooks.Open(spreadsheetLocation);
var workSheet1 = (Microsoft.Office.Interop.Excel.Worksheet)workBook.Sheets["Data"];
var workSheet2 = (Microsoft.Office.Interop.Excel.Worksheet)workBook.Sheets.Add();
Microsoft.Office.Interop.Excel.Range last = workSheet1.Cells.SpecialCells(Microsoft.Office.Interop.Excel.XlCellType.xlCellTypeLastCell, Type.Missing);
Microsoft.Office.Interop.Excel.Range range = workSheet1.get_Range("A1", last);
Microsoft.Office.Interop.Excel.PivotCaches pivotCaches = null;
Microsoft.Office.Interop.Excel.PivotCache pivotCache = null;
Microsoft.Office.Interop.Excel.PivotTable pivotTable = null;
Microsoft.Office.Interop.Excel.PivotFields pivotFields = null;
Microsoft.Office.Interop.Excel.PivotField filterField = null;
Microsoft.Office.Interop.Excel.PivotField accNumField = null;
Microsoft.Office.Interop.Excel.PivotField amountPaidField = null;
pivotCaches = workBook.PivotCaches();
pivotCache = pivotCaches.Create(XlPivotTableSourceType.xlDatabase, range);
pivotTable = pivotCache.CreatePivotTable(workSheet2.Cells[1,1]);
pivotFields = (Microsoft.Office.Interop.Excel.PivotFields)pivotTable.PivotFields();
amountPaidField = (Microsoft.Office.Interop.Excel.PivotField)pivotFields.Item("AmountPaid");
amountPaidField.Orientation = Microsoft.Office.Interop.Excel.XlPivotFieldOrientation.xlDataField;
amountPaidField.NumberFormat = "$#,###,###.00";
accNumField = (Microsoft.Office.Interop.Excel.PivotField)pivotFields.Item("AccNumber");
accNumField.Orientation = Microsoft.Office.Interop.Excel.XlPivotFieldOrientation.xlRowField;
filterField = (Microsoft.Office.Interop.Excel.PivotField)pivotFields.Item("AccDate");
filterField.Orientation = Microsoft.Office.Interop.Excel.XlPivotFieldOrientation.xlPageField;
filterField.EnableMultiplePageItems = true;
filterField.PivotFilters.Add2(XlPivotFilterType.xlDateBetween, Type.Missing, DateTime.Now.AddDays(-30), DateTime.Now.AddDays(-20));
#First it deletes two rows and then it creates a pivot table#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Office.Interop.Excel;
namespace ConsoleApplication4
{
class Program
{
public static string Column(int column)
{
column--;
if (column >= 0 && column < 26)
return ((char)('A' + column)).ToString();
else if (column > 25)
return Column(column / 26) + Column(column % 26 + 1);
else
throw new Exception("Invalid Column #" + (column + 1).ToString());
}
static void Main(string[] args)
{
try
{
string path = #"C:\Users\UX155512\Documents\Book1fd.xlsx";
var excelFile = new Application();
Workbook workBook = excelFile.Workbooks.Open(path);
Worksheet workSheet = workBook.Worksheets[1];
Worksheet pivotSheet = workBook.Worksheets.Add(
System.Reflection.Missing.Value,
workBook.Worksheets[workBook.Worksheets.Count],
1,
System.Reflection.Missing.Value);
Range last = workSheet.Cells.SpecialCells(XlCellType.xlCellTypeLastCell, Type.Missing);
int lastRow = last.Row;
int lastCol = last.Column;
string lastColVal = Column(lastCol);
string lastFilledCol = lastColVal + lastRow.ToString();
Console.WriteLine(lastFilledCol);
Console.WriteLine(lastColVal);
Console.WriteLine(lastRow);
Console.WriteLine(lastCol);
for (int i = 1; i <= lastRow; i++)
{
if (workSheet.Cells[1][i].Value == ("HDR"))
{
workSheet.Rows[i].Delete();
Console.WriteLine("The Row Containing HDR has been deleted");
}
if (workSheet.Cells[1][i].Value == ("TRL"))
{
workSheet.Rows[i].Delete();
Console.WriteLine("The Row Containing TLR has been deleted");
}
}
Range lastRange = workSheet.Range["A1", lastFilledCol];
pivotSheet.Name = "Pivot Table";
Range range = pivotSheet.Cells[1, 1];
PivotCache pivotCache = (PivotCache)workBook.PivotCaches().Add(XlPivotTableSourceType.xlDatabase, lastRange);
PivotTable pivotTable = (PivotTable)pivotSheet.PivotTables().Add(PivotCache: pivotCache, TableDestination: range);
PivotField pivotField = (PivotField)pivotTable.PivotFields("Plan Number");
pivotField.Orientation = XlPivotFieldOrientation.xlRowField;
PivotField pivotField2 = (PivotField)pivotTable.PivotFields("Source");
pivotField2.Orientation = XlPivotFieldOrientation.xlColumnField;
PivotField pivotField3 = (PivotField)pivotTable.PivotFields("Total");
pivotField3.Orientation = XlPivotFieldOrientation.xlDataField;
pivotField3.Function = XlConsolidationFunction.xlSum;
workBook.SaveAs(#"C:\Users\UX155512\Documents\Excel Dump\Trial9.xlsx");
workBook.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.Read();
}
}
}
As mentioned above by Asger, the filter can't be added to a page field. Instead, the pivot item's visibility property has to be set.
var pivotItems = filterField.PivotItems();
DateTime date = Convert.ToDateTime(item.Name);
foreach (var item in pivotItems)
{
item.Visible = false;
if (date < DateTime.Now.AddDays(-30) || date > DateTime.Now.AddDays(-20))
{
item.Visible = true;
}
}
The best way to find the answer to pretty much ANY interop question is to record a macro then examine the source.
I use the below code to read data from an excel file into a DataTable object for further use. Since it processes from 100k to 500k entries, the reading can get a bit slow. Is there something I could change in my code in order to optimize the process ? Code is below.
public static DataTable ReadAsDataTable(string filePath)
{
DataTable dataTable = new DataTable();
using (SpreadsheetDocument spreadSheetDocument = SpreadsheetDocument.Open(filePath, false))
{
WorkbookPart workbookPart = spreadSheetDocument.WorkbookPart;
IEnumerable<Sheet> sheets = spreadSheetDocument.WorkbookPart.Workbook.GetFirstChild<Sheets>().Elements<Sheet>();
string relationshipId = sheets.First().Id.Value;
WorksheetPart worksheetPart = (WorksheetPart)spreadSheetDocument.WorkbookPart.GetPartById(relationshipId);
Worksheet workSheet = worksheetPart.Worksheet;
SheetData sheetData = workSheet.GetFirstChild<SheetData>();
IEnumerable<Row> rows = sheetData.Descendants<Row>();
foreach (Cell cell in rows.ElementAt(0))
{
dataTable.Columns.Add(GetCellValue(spreadSheetDocument, cell));
}
foreach (Row row in rows)
{
DataRow dataRow = dataTable.NewRow();
for (int i = 0; i < row.Descendants<Cell>().Count(); i++)
{
dataRow[i] = GetCellValue(spreadSheetDocument, row.Descendants<Cell>().ElementAt(i));
}
dataTable.Rows.Add(dataRow);
}
}
dataTable.Rows.RemoveAt(0);
return dataTable;
}
private static string GetCellValue(SpreadsheetDocument document, Cell cell)
{
SharedStringTablePart stringTablePart = document.WorkbookPart.SharedStringTablePart;
string value = cell.CellValue.InnerXml;
if (cell.DataType != null && cell.DataType.Value == CellValues.SharedString)
{
return stringTablePart.SharedStringTable.ChildElements[Int32.Parse(value)].InnerText;
}
else
{
return value;
}
}
I'm not sure what's the compiler behavior on this or the performance characteristics of that API, but would it help if you call row.Descendants<Cell>() only once? It seems like something the compiler could optimize, but there may be side effects involved, so it doesn't do anything.
foreach (Row row in rows)
{
var cells = row.Descendants<Cell>().ToArray();
DataRow dataRow = dataTable.NewRow();
for (int i = 0; i < cells.Length; i++)
{
dataRow[i] = GetCellValue(spreadSheetDocument, cells[i]);
}
dataTable.Rows.Add(dataRow);
}
I have an issue at converting from Excel file to XML file. When I convert the info in table tags, it converts in <table1></table1> <table1></table1> <table1></table1>but I need to convert each column in <table1></table1><table2></table2>...
The code is the following.
private DataTable ReadExcelFile(string filename)
{
// Initialize an instance of DataTable
DataTable dt = new DataTable();
try
{
// Use SpreadSheetDocument class of Open XML SDK to open excel file
using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Open(filename, false))
{
// Get Workbook Part of Spread Sheet Document
WorkbookPart workbookPart = spreadsheetDocument.WorkbookPart;
// Get all sheets in spread sheet document
// IEnumerable Interface
// Exposes an enumerator, which supports a simple iteration over a non-generic collection.
IEnumerable<Sheet> sheetcollection = spreadsheetDocument.WorkbookPart.Workbook.GetFirstChild<Sheets>().Elements<Sheet>();
// Get relationship Id
string relationshipId = sheetcollection.First().Id.Value;
// Get sheet1 Part of Spread Sheet Document
WorksheetPart worksheetPart = (WorksheetPart)spreadsheetDocument.WorkbookPart.GetPartById(relationshipId);
// Get Data in Excel file
SheetData sheetData = worksheetPart.Worksheet.Elements<SheetData>().First();
IEnumerable<Row> rowcollection = sheetData.Descendants<Row>();
if (rowcollection.Count() == 0)
{
return dt;
}
// Add columns
foreach (Cell cell in rowcollection.ElementAt(0))
{
dt.Columns.Add(GetValueOfCell(spreadsheetDocument, cell));
}
// Add rows into DataTable
foreach (Row row in rowcollection)
{
DataRow temprow = dt.NewRow();
int columnIndex = 0;
foreach (Cell cell in row.Descendants<Cell>())
{
// Get Cell Column Index
int cellColumnIndex = GetColumnIndex(GetColumnName(cell.CellReference));
if (columnIndex < cellColumnIndex)
{
do
{
temprow[columnIndex] = string.Empty;
columnIndex++;
}
while (columnIndex < cellColumnIndex);
}
temprow[columnIndex] = GetValueOfCell(spreadsheetDocument, cell);
columnIndex++;
}
// Add the row to DataTable
// the rows include header row
dt.Rows.Add(temprow);
}
}
// Here remove header row
dt.Rows.RemoveAt(0);
return dt;
}
catch (IOException ex)
{
throw new IOException(ex.Message);
}
}
private static string GetValueOfCell(SpreadsheetDocument spreadsheetdocument, Cell cell)
{
// Get value in Cell
SharedStringTablePart sharedString = spreadsheetdocument.WorkbookPart.SharedStringTablePart;
if (cell.CellValue == null)
{
return string.Empty;
}
string cellValue = cell.CellValue.InnerText;
// The condition that the Cell DataType is SharedString
if (cell.DataType != null && cell.DataType.Value == CellValues.SharedString)
{
return sharedString.SharedStringTable.ChildElements[int.Parse(cellValue)].InnerText;
}
else
{
return cellValue;
}
}
private string GetColumnName(string cellReference)
{
// Create a regular expression to match the column name of cell
Regex regex = new Regex("[A-Za-z]+");
Match match = regex.Match(cellReference);
return match.Value;
}
private int GetColumnIndex(string columnName)
{
int columnIndex = 0;
int factor = 1;
// From right to left
for (int position = columnName.Length - 1; position >= 0; position--)
{
// For letters
if (Char.IsLetter(columnName[position]))
{
columnIndex += factor * ((columnName[position] - 'A') + 1) - 1;
factor *= 26;
}
}
return columnIndex;
}
public string GetXML(string filename)
{
using (DataSet ds = new DataSet())
{
ds.Tables.Add(this.ReadExcelFile(filename));
return ds.GetXml();
}
}
May somebody help me out with this issue?
Or any idea how to create a custom tags?
Thanks in advance.
I need a solution to export a dataset to an excel file without any asp code (HttpResonpsne...) but i did not find a good example to do this...
Best thanks in advance
I've created a class that exports a DataGridView or DataTable to an Excel file. You can probably change it a bit to make it use your DataSet instead (iterating through the DataTables in it). It also does some basic formatting which you could also extend.
To use it, simply call ExcelExport, and specify a filename and whether to open the file automatically or not after exporting. I also could have made them extension methods, but I didn't. Feel free to.
Note that Excel files can be saved as a glorified XML document and this makes use of that.
EDIT: This used to use a vanilla StreamWriter, but as pointed out, things would not be escaped correctly in many cases. Now it uses a XmlWriter, which will do the escaping for you.
The ExcelWriter class wraps an XmlWriter. I haven't bothered, but you might want to do a bit more error checking to make sure you can't write cell data before starting a row, and such. The code is below.
public class ExcelWriter : IDisposable
{
private XmlWriter _writer;
public enum CellStyle { General, Number, Currency, DateTime, ShortDate };
public void WriteStartDocument()
{
if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
_writer.WriteProcessingInstruction("mso-application", "progid=\"Excel.Sheet\"");
_writer.WriteStartElement("ss", "Workbook", "urn:schemas-microsoft-com:office:spreadsheet");
WriteExcelStyles();
}
public void WriteEndDocument()
{
if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
_writer.WriteEndElement();
}
private void WriteExcelStyleElement(CellStyle style)
{
_writer.WriteStartElement("Style", "urn:schemas-microsoft-com:office:spreadsheet");
_writer.WriteAttributeString("ID", "urn:schemas-microsoft-com:office:spreadsheet", style.ToString());
_writer.WriteEndElement();
}
private void WriteExcelStyleElement(CellStyle style, string NumberFormat)
{
_writer.WriteStartElement("Style", "urn:schemas-microsoft-com:office:spreadsheet");
_writer.WriteAttributeString("ID", "urn:schemas-microsoft-com:office:spreadsheet", style.ToString());
_writer.WriteStartElement("NumberFormat", "urn:schemas-microsoft-com:office:spreadsheet");
_writer.WriteAttributeString("Format", "urn:schemas-microsoft-com:office:spreadsheet", NumberFormat);
_writer.WriteEndElement();
_writer.WriteEndElement();
}
private void WriteExcelStyles()
{
_writer.WriteStartElement("Styles", "urn:schemas-microsoft-com:office:spreadsheet");
WriteExcelStyleElement(CellStyle.General);
WriteExcelStyleElement(CellStyle.Number, "General Number");
WriteExcelStyleElement(CellStyle.DateTime, "General Date");
WriteExcelStyleElement(CellStyle.Currency, "Currency");
WriteExcelStyleElement(CellStyle.ShortDate, "Short Date");
_writer.WriteEndElement();
}
public void WriteStartWorksheet(string name)
{
if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
_writer.WriteStartElement("Worksheet", "urn:schemas-microsoft-com:office:spreadsheet");
_writer.WriteAttributeString("Name", "urn:schemas-microsoft-com:office:spreadsheet", name);
_writer.WriteStartElement("Table", "urn:schemas-microsoft-com:office:spreadsheet");
}
public void WriteEndWorksheet()
{
if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
_writer.WriteEndElement();
_writer.WriteEndElement();
}
public ExcelWriter(string outputFileName)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
_writer = XmlWriter.Create(outputFileName, settings);
}
public void Close()
{
if (_writer == null) throw new InvalidOperationException("Already closed.");
_writer.Close();
_writer = null;
}
public void WriteExcelColumnDefinition(int columnWidth)
{
if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
_writer.WriteStartElement("Column", "urn:schemas-microsoft-com:office:spreadsheet");
_writer.WriteStartAttribute("Width", "urn:schemas-microsoft-com:office:spreadsheet");
_writer.WriteValue(columnWidth);
_writer.WriteEndAttribute();
_writer.WriteEndElement();
}
public void WriteExcelUnstyledCell(string value)
{
if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
_writer.WriteStartElement("Cell", "urn:schemas-microsoft-com:office:spreadsheet");
_writer.WriteStartElement("Data", "urn:schemas-microsoft-com:office:spreadsheet");
_writer.WriteAttributeString("Type", "urn:schemas-microsoft-com:office:spreadsheet", "String");
_writer.WriteValue(value);
_writer.WriteEndElement();
_writer.WriteEndElement();
}
public void WriteStartRow()
{
if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
_writer.WriteStartElement("Row", "urn:schemas-microsoft-com:office:spreadsheet");
}
public void WriteEndRow()
{
if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
_writer.WriteEndElement();
}
public void WriteExcelStyledCell(object value, CellStyle style)
{
if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
_writer.WriteStartElement("Cell", "urn:schemas-microsoft-com:office:spreadsheet");
_writer.WriteAttributeString("StyleID", "urn:schemas-microsoft-com:office:spreadsheet", style.ToString());
_writer.WriteStartElement("Data", "urn:schemas-microsoft-com:office:spreadsheet");
switch (style)
{
case CellStyle.General:
_writer.WriteAttributeString("Type", "urn:schemas-microsoft-com:office:spreadsheet", "String");
break;
case CellStyle.Number:
case CellStyle.Currency:
_writer.WriteAttributeString("Type", "urn:schemas-microsoft-com:office:spreadsheet", "Number");
break;
case CellStyle.ShortDate:
case CellStyle.DateTime:
_writer.WriteAttributeString("Type", "urn:schemas-microsoft-com:office:spreadsheet", "DateTime");
break;
}
_writer.WriteValue(value);
// tag += String.Format("{1}\"><ss:Data ss:Type=\"DateTime\">{0:yyyy\\-MM\\-dd\\THH\\:mm\\:ss\\.fff}</ss:Data>", value,
_writer.WriteEndElement();
_writer.WriteEndElement();
}
public void WriteExcelAutoStyledCell(object value)
{
if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
//write the <ss:Cell> and <ss:Data> tags for something
if (value is Int16 || value is Int32 || value is Int64 || value is SByte ||
value is UInt16 || value is UInt32 || value is UInt64 || value is Byte)
{
WriteExcelStyledCell(value, CellStyle.Number);
}
else if (value is Single || value is Double || value is Decimal) //we'll assume it's a currency
{
WriteExcelStyledCell(value, CellStyle.Currency);
}
else if (value is DateTime)
{
//check if there's no time information and use the appropriate style
WriteExcelStyledCell(value, ((DateTime)value).TimeOfDay.CompareTo(new TimeSpan(0, 0, 0, 0, 0)) == 0 ? CellStyle.ShortDate : CellStyle.DateTime);
}
else
{
WriteExcelStyledCell(value, CellStyle.General);
}
}
#region IDisposable Members
public void Dispose()
{
if (_writer == null)
return;
_writer.Close();
_writer = null;
}
#endregion
}
Then you can export your DataTable using the following:
public static void ExcelExport(DataTable data, String fileName, bool openAfter)
{
//export a DataTable to Excel
DialogResult retry = DialogResult.Retry;
while (retry == DialogResult.Retry)
{
try
{
using (ExcelWriter writer = new ExcelWriter(fileName))
{
writer.WriteStartDocument();
// Write the worksheet contents
writer.WriteStartWorksheet("Sheet1");
//Write header row
writer.WriteStartRow();
foreach (DataColumn col in data.Columns)
writer.WriteExcelUnstyledCell(col.Caption);
writer.WriteEndRow();
//write data
foreach (DataRow row in data.Rows)
{
writer.WriteStartRow();
foreach (object o in row.ItemArray)
{
writer.WriteExcelAutoStyledCell(o);
}
writer.WriteEndRow();
}
// Close up the document
writer.WriteEndWorksheet();
writer.WriteEndDocument();
writer.Close();
if (openAfter)
OpenFile(fileName);
retry = DialogResult.Cancel;
}
}
catch (Exception myException)
{
retry = MessageBox.Show(myException.Message, "Excel Export", MessageBoxButtons.RetryCancel, MessageBoxIcon.Asterisk);
}
}
}
The following site demonstrates how to export a DataSet (or DataTable or List<>) into a "genuine" Excel 2007 .xlsx file.
It uses the OpenXML libraries, so you don't need to have Excel installed on your server.
C# ExportToExcel library
All of the source code is provided, free of charge, along with instructions using it with ASP.NET, ASP.NET Core 2+ or regular C#.
It's very easy to add to your own applications, you just need to call one function, passing in an Excel filename, and your data source:
DataSet ds = CreateSampleData();
string excelFilename = "C:\\Sample.xlsx";
CreateExcelFile.CreateExcelDocument(ds, excelFilename);
Hope this helps.
Creating excel files in .NET applications is quite common and similar questions have been asked several times before. For instance here and here. The last question asks about reading excel files, but most suggested solutions should work both ways.
This was a post with a really helpful top answer, but I found it was lacking because there was no simple way to import the XML file back into a datatable. I ended up having to write my own, and thought I would share it here in case anyone else was in the same boat (google was exceptionally unhelpful in that regard):
public static DataTable ImportExcelXML(string Filename)
{
//create a new dataset to load in the XML file
DataSet DS = new DataSet();
//Read the XML file into the dataset
DS.ReadXml(Filename);
//Create a new datatable to store the raw Data
DataTable Raw = new DataTable();
//assign the raw data from the file to the datatable
Raw = DS.Tables["Data"];
//count the number of columns in the XML file
int ColumnNumber = Raw.Columns.Count;
//create a datatable to store formatted Import Data
DataTable ImportData = new DataTable();
//create a string list to store the cell data of each row
List<string> RowData = new List<string>();
//loop through each row in the raw data table
for (int Counter = 0; Counter < Raw.Rows.Count; Counter++)
{
//if the data in the row is a colum header
if (Counter < ColumnNumber)
{
//add the column name to our formatted datatable
ImportData.Columns.Add(Raw.Rows[Counter].ItemArray.GetValue(1).ToString());
}
else
{
//if the row # (1 row = 1 cell from the excel file) from the raw datatable is divisable evenly by the number of columns in the formated import datatable AND this is not the 1st row of the raw table data after the headers
if ((Counter % ColumnNumber == 0) && (Counter != ColumnNumber))
{
//add the row we just built to the formatted import datatable
ImportData.Rows.Add(GenerateRow(ImportData, RowData));
//clear rowdata list in preperation for the next row
RowData.Clear();
}
//add the current cell data value from the raw datatable to the string list of cell values for the next row to be added to the formatted input datatable
RowData.Add(Raw.Rows[Counter].ItemArray.GetValue(1).ToString());
}
}
//add the final row
ImportData.Rows.Add(GenerateRow(ImportData, RowData));
return ImportData;
}
public static DataRow GenerateRow(DataTable ImportData, List<string> RowData)
{
//create a counter to keep track of the column position during row composition
int ColumnPosition = 0;
//make a new datarow based on the schema of the formated import datatable
DataRow NewRow = ImportData.NewRow();
//for each string cell value collected for the RowData list for this row
foreach (string CellData in RowData)
{
//add the cell value to the new datarow
NewRow[ImportData.Columns[ColumnPosition].ColumnName] = CellData;
//incriment column position in the new row
ColumnPosition++;
}
//return the generated row
return NewRow;
}
the code have problem with null values.
public void WriteExcelAutoStyledCell(object value)
{
//solve null values
if (value is DBNull) return;
I would have added this to the comments but I am new to stack so I am unable to comment. Using lc.'s solution I added another function that tests the strings characters for invalid XML characters. When I was exporting to excel on occasion there were characters that were found that were causing the export to fail.
You will need to modify one of the functions that is in lc's code.
public void WriteExcelAutoStyledCell(object value)
{
if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
string newValue = string.Empty;
try
{
//write the <ss:Cell> and <ss:Data> tags for something
if (value is Int16 || value is Int32 || value is Int64 || value is SByte ||
value is UInt16 || value is UInt32 || value is UInt64 || value is Byte)
{
WriteExcelStyledCell(value, CellStyle.Number);
}
else if (value is Single || value is Double || value is Decimal) //we'll assume it's a currency
{
WriteExcelStyledCell(value, CellStyle.Currency);
}
else if (value is DateTime)
{
//check if there's no time information and use the appropriate style
WriteExcelStyledCell(value, ((DateTime)value).TimeOfDay.CompareTo(new TimeSpan(0, 0, 0, 0, 0)) == 0 ? CellStyle.ShortDate : CellStyle.DateTime);
}
else
{
newValue = CheckXmlCompatibleValues(value.ToString()).ToString();
WriteExcelStyledCell(newValue, CellStyle.General);
}
}
catch (Exception thisException)
{
throw new InvalidOperationException(thisException.Message.ToString());
}
}
And add this function to 'ExcelWriter' class
public string CheckXmlCompatibleValues(string value)
{
string newValue = string.Empty;
bool found = false;
foreach (char c in value)
{
if (XmlConvert.IsXmlChar(c))
newValue += c.ToString();
else
found = true;
}
return newValue.ToString();
}
lc. Thanks for the code!
using XL = Microsoft.Office.Interop.Excel;
using System.Reflection;
public static void Datasource(DataTable dt)
{
XL.Application oXL;
XL._Workbook oWB;
XL._Worksheet oSheet;
XL.Range oRng;
try
{
oXL = new XL.Application();
Application.DoEvents();
oXL.Visible = false;
//Get a new workbook.
oWB = (XL._Workbook)(oXL.Workbooks.Add(Missing.Value));
oSheet = (XL._Worksheet)oWB.ActiveSheet;
//System.Data.DataTable dtGridData=ds.Tables[0];
int iRow = 2;
if (dt.Rows.Count > 0)
{
for (int j = 0; j < dt.Columns.Count; j++)
{
oSheet.Cells[1, j + 1] = dt.Columns[j].ColumnName;
}
// For each row, print the values of each column.
for (int rowNo = 0; rowNo < dt.Rows.Count; rowNo++)
{
for (int colNo = 0; colNo < dt.Columns.Count; colNo++)
{
oSheet.Cells[iRow, colNo + 1] = dt.Rows[rowNo][colNo].ToString();
}
iRow++;
}
iRow++;
}
oRng = oSheet.get_Range("A1", "IV1");
oRng.EntireColumn.AutoFit();
oXL.Visible = true;
}
catch (Exception theException)
{
throw theException;
}
finally
{
oXL = null;
oWB = null;
oSheet = null;
oRng = null;
}
}
Import from Excel to datatable:
DataTable dtTable = new DataTable();
DataColumn col = new DataColumn("Rfid");
dtTable.Columns.Add(col);
DataRow drRow;
Microsoft.Office.Interop.Excel.Application ExcelObj =
new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook theWorkbook =
ExcelObj.Workbooks.Open(txt_FilePath.Text, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
Microsoft.Office.Interop.Excel.Sheets sheets = theWorkbook.Worksheets;
try
{
for (int sht = 1; sht <= sheets.Count; sht++)
{
Microsoft.Office.Interop.Excel.Worksheet worksheet =
(Microsoft.Office.Interop.Excel.Worksheet)sheets.get_Item(sht);
for (int i = 2; i <= worksheet.UsedRange.Rows.Count; i++)
{
Microsoft.Office.Interop.Excel.Range range = worksheet.get_Range("A" + i.ToString(), "B" + i.ToString());
System.Array myvalues = (System.Array)range.Cells.Value2;
String name = Convert.ToString(myvalues.GetValue(1, 1));
if (string.IsNullOrEmpty(name) == false)
{
drRow = dtTable.NewRow();
drRow["Rfid"] = name;
dtTable.Rows.Add(drRow);
}
}
Marshal.ReleaseComObject(worksheet);
worksheet = null;
}
return dtTable;
}
catch
{
throw;
}
finally
{
// Marshal.ReleaseComObject(worksheet);
Marshal.ReleaseComObject(sheets);
Marshal.ReleaseComObject(theWorkbook);
Marshal.ReleaseComObject(ExcelObj);
//worksheet = null;
sheets = null;
theWorkbook = null;
ExcelObj = null;
}
Microsoft has a built in solution for Importing/Exporting Excel files. It's not the most straightforward library but it generally works better than the others listed above.
The library required to do this is included in Office and can be found under the list of Framework assemblies at Microsoft.Office.Interop.Excel.
Here is some example code:
using Excel = Microsoft.Office.Interop.Excel;
Excel.Application app = new Excel.Application();
//Open existing workbook
//Excel.Workbook workbook = xlApp.Workbooks.Open(fileName);
//Create new workbook
Excel.Workbook workbook = app.Workbooks.Add();
Excel.Worksheet worksheet = workbook.ActiveSheet;
worksheet.Cells[1,1] = "Hello world!"; // Indexes start at 1, because Excel
workbook.SaveAs("C:\\MyWorkbook.xlsx");
workbook.Close();
app.Quit();