Время на прочтение
7 мин
Количество просмотров 69K
В современном мире разработки приложений нередко встает необходимость работы с Excel документами. Чаще всего это разного рода отчеты, но иногда xls/x файлы используются в качестве хранилища данных. Например, если пользователь должен иметь возможность загрузить данные в приложение или выгрузить, в человеко-читаемом виде, Excel де-факто является стандартом. Относительно дружелюбный интерфейс, прозрачная структура, в купе с его распространенностью… трудно навскидку назвать решение лучше.
Однако, у многих Excel до сих пор ассоциируется с чем-то тяжелым, неповоротливым и сложным. Давайте посмотрим, как мы — обычные C# разработчики, можем легко сформировать простой Excel документ, на примере табличного отчета.
Историческая справка
Времена, когда доминировал проприетарный формат .xls(Excel Binary File Format) давно прошли и сейчас мы имеем только .xlsx(Excel Workbook), в рамках Office Open XML. Последний представляет собой обычный .zip архив с XML файлами. Не будем углубляться в его структуру, я искренне надеюсь что вам это никогда не понадобится.
На github, и не только, можно найти ряд библиотек, бесплатных и не только. Пожалуй самой популярной является EPPlus. До определенной степени, она довольно хорошо отражает концепцию Excel, именно по этому я всегда использую EPPlus. Версия 4 полностью бесплатна, начиная с 5‐й версии вам потребуется приобрести лицензию для коммерческого использования.
Задача
Итак, предположим, продукт-мэнеджеру ударила в голову идея того, что возможность выгружать некий отчет в формате Excel увеличит кол-во пользователей на 100500%. Проджет-менеджер решает выкатить эту киллер-фичу как хотфикс прямо сегодня — ведь работы всего на пару часов.
Сам по себе, отчет содержит краткое описание компании и историю изменения некоторых экономических показателей. Для простоты все свойства компании — строки. Экономические показатели — большие целые числа и числа с плавающей точкой, а также даты. Предположим, что где-то в недрах микросервисного backend-да есть сервис-генератор подобных отчетов, например по id компании. Однако, поскольку id нет смысла выводить пользователю, идентификатор отсутствует в самой модели отчета.
Аналитик, в свою очередь, выдает задачу с феноменально точным описанием — «Сгенерировать excel отчет на базе данных MarketReport». Что ж, для нашего примера, создадим заглушку — генератор фейковых данных:
Первый запуск
Подключим EPPlus версии 4.5.3.3 и создадим базовую обвязку для будущего генератора.
Сердцем генератора будет метод Generate. ExcelPackage это модель документа, через которую мы и будем осуществлять все взаимодействия с ним. Также имеется конструктор для передачи пути к файлу или потока.
В методе main создается генератор отчетов, а также генератор Excel файлов. Далее полученный файл просто записывается на диск.
При попытке запустить приложение, получаем exception:InvalidOperationException: The workbook must contain at least one worksheet
Все правильно, Excel документ не может существовать без страниц, должна быть хотя бы одна. Добавляем ее, все интуитивно понятно:
var sheet = package.Workbook.Worksheets
.Add("Market Report");
Запускаем снова и… вот оно! Теперь наше приложение генерирует документ и, хотя там еще ничего нет, он уже весит 2,5KB — значит мы работаем с Excel правильно и все идет как надо.
Вывод данных
Давайте выведем основную информацию по компании в шапку. Для доступа к конкретной ячейки объект Cells на странице пакета снабжен удобным индексатором. При этом, до конкретной ячейки можно достучаться как через номер строки и столбца, так и по привычному всем буквенно-числовому коду:
sheet.Cells["B2"].Value = "Company:";
sheet.Cells[2, 3].Value = report.Company.Name;
Полный код вывода шапки.
sheet.Cells["B2"].Value = "Company:";
sheet.Cells[2, 3].Value = report.Company.Name;
sheet.Cells["B3"].Value = "Location:";
sheet.Cells["C3"].Value = $"{report.Company.Address}, " +
$"{report.Company.City}, " +
$"{report.Company.Country}";
sheet.Cells["B4"].Value = "Sector:";
sheet.Cells["C4"].Value = report.Company.Sector;
sheet.Cells["B5"].Value = report.Company.Description;
Для вывода исторических данных понадобится как минимум шапка таблицы и цикл по массиву History:
sheet.Cells[8, 2, 8, 4].LoadFromArrays(new object[][]{ new []{"Capitalization", "SharePrice", "Date"} });
var row = 9;
var column = 2;
foreach (var item in report.History)
{
sheet.Cells[row, column].Value = item.Capitalization;
sheet.Cells[row, column + 1].Value = item.SharePrice;
sheet.Cells[row, column + 2].Value = item.Date;
row++;
}
Предлагаю обратить внимание на метод LoadFromArrays, который заполняет диапазон ячеек рваным(зубчатым) массивом. Здесь мы можем видеть, что типизация теряется и передавая массив object мы ожидаем что EPPlus в конечном итоге использует ToString, чтобы записать переданное в ячейки.
Стилизация
Если вы прямо сейчас откроете документ, то вы возможно увидите не то, что хотелось бы отдать в продакшн в пятницу вечером.
Как это выглядит

Во-первых, шапка никак не выделяется, во-вторых таблица не имеет границ… выравнивание пляшет, даты отображаются магическими числами, а капитализация «уходит в какую-то математику» — как это прокомментировал аналитик.
Да, на все эти красивости у нас уйдет больше года кода, чем на сам вывод данных, и, в конечном тоге, получившаяся каша из логики вывода данных и разметки заставит некоторых усомниться в их компетентности… но, мы же backend разработчики, так давайте сверстаем Excel Sheet!
Размер ячеек
Из коробки у нас есть возможность сделать автофит а так же вручную выставить ширину в соответствии с нашей ситуацией. А ситуация у нас не самая хорошая — по задумке аналитика в шапке у ячеек должен быть автофит, а у ячеек таблицы — тоже автофит. Так в чем же подвох?
Если вы когда-нибудь до этого открывали Excel, то возможно знаете, что ширина ячеек не может отличаться в рамках столбца и автофит будет по самому широкому контенту ячейки. Однако, простые вещи бывает нетак то просто объяснить… Но если вы справитесь, то вот как это будет выглядеть в коде:
sheet.Cells[1, 1, row, column + 2].AutoFitColumns();
sheet.Column(2).Width = 14;
sheet.Column(3).Width = 12;
Формат данных
Как и большая часть стиля ячейки, он задается через одноименное свойство Style. Обратите внимание на вычисление 3-го аргумента индексатора. Это звоночек некачественного кода, но к этому мы вернемся в позже…
sheet.Cells[9, 4, 9 + report.History.Length, 4].Style.Numberformat.Format = "yyyy";
sheet.Cells[9, 2, 9 + report.History.Length, 2].Style.Numberformat.Format = "### ### ### ##0";
Выравнивание
Его можно задать как на ячейке, так и на диапазоне. На самом деле, для EPPlus, это одна и та же сущность — некий ExcelRange, описывающий диапазон ячеек, в том числе и со всего 1 ячейкой.
sheet.Column(2).Style.HorizontalAlignment = ExcelHorizontalAlignment.Left;
sheet.Cells[8, 3, 8 + report.History.Length, 3].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
Стиль текста
Также легко задается, используя Style.Font, кстати, здесь, на 2-й строчке, мы впервые указываем диапазон так, как привыкли его видеть пользователи Excel:
sheet.Cells[8, 2, 8, 4].Style.Font.Bold = true;
sheet.Cells["B2:C4"].Style.Font.Bold = true;
Границы
Задаем стиль линии, а также ее толщину. К этому моменту от кол-ва магических чисел-параметров индексатора уже рябит в глазах, но мы уже на финишной прямой… не так ли?
sheet.Cells[8, 2, 8 + report.History.Length, 4].Style.Border.BorderAround(ExcelBorderStyle.Double);
sheet.Cells[8, 2, 8, 4].Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
График
«Ну что за отчет без графиков, верно, Карл?» — ловко подметит специалист по тестированию, и не важно, что этого не было в ТЗ а на часах уже половина 9-го…
Хотя график как сущность сам по себе сложнее таблиц и с графиками мы не работаем каждый день, EPPlus предоставляет довольно понятный API. Давайте добавим простейший график, отражающий рост капитализации:
var capitalizationChart = sheet.Drawings.AddChart("FindingsChart", OfficeOpenXml.Drawing.Chart.eChartType.Line);
capitalizationChart.Title.Text = "Capitalization";
capitalizationChart.SetPosition(7, 0, 5, 0);
capitalizationChart.SetSize(800, 400);
var capitalizationData = (ExcelChartSerie)(capitalizationChart.Series.Add(sheet.Cells["B9:B28"], sheet.Cells["D9:D28"]));
capitalizationData.Header = report.Company.Currency;
Еще, может понадобиться защитить страницу от редактирования:
sheet.Protection.IsProtected = true;
На этом все, репозиторий с рабочим приложением находится здесь.
Заключение
О чем говорит финальная версия метода Generate?
public byte[] Generate(MarketReport report)
{
var package = new ExcelPackage();
var sheet = package.Workbook.Worksheets
.Add("Market Report");
sheet.Cells["B2"].Value = "Company:";
sheet.Cells[2, 3].Value = report.Company.Name;
sheet.Cells["B3"].Value = "Location:";
sheet.Cells["C3"].Value = $"{report.Company.Address}, " +
$"{report.Company.City}, " +
$"{report.Company.Country}";
sheet.Cells["B4"].Value = "Sector:";
sheet.Cells["C4"].Value = report.Company.Sector;
sheet.Cells["B5"].Value = report.Company.Description;
sheet.Cells[8, 2, 8, 4].LoadFromArrays(new object[][]{ new []{"Capitalization", "SharePrice", "Date"} });
var row = 9;
var column = 2;
foreach (var item in report.History)
{
sheet.Cells[row, column].Value = item.Capitalization;
sheet.Cells[row, column + 1].Value = item.SharePrice;
sheet.Cells[row, column + 2].Value = item.Date;
row++;
}
sheet.Cells[1, 1, row, column + 2].AutoFitColumns();
sheet.Column(2).Width = 14;
sheet.Column(3).Width = 12;
sheet.Cells[9, 4, 9+ report.History.Length, 4].Style.Numberformat.Format = "yyyy";
sheet.Cells[9, 2, 9+ report.History.Length, 2].Style.Numberformat.Format = "### ### ### ##0";
sheet.Column(2).Style.HorizontalAlignment = ExcelHorizontalAlignment.Left;
sheet.Cells[8, 3, 8 + report.History.Length, 3].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
sheet.Column(4).Style.HorizontalAlignment = ExcelHorizontalAlignment.Right;
sheet.Cells[8, 2, 8, 4].Style.Font.Bold = true;
sheet.Cells["B2:C4"].Style.Font.Bold = true;
sheet.Cells[8, 2, 8 + report.History.Length, 4].Style.Border.BorderAround(ExcelBorderStyle.Double);
sheet.Cells[8, 2, 8, 4].Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
var capitalizationChart = sheet.Drawings.AddChart("FindingsChart", OfficeOpenXml.Drawing.Chart.eChartType.Line);
capitalizationChart.Title.Text = "Capitalization";
capitalizationChart.SetPosition(7, 0, 5, 0);
capitalizationChart.SetSize(800, 400);
var capitalizationData = (ExcelChartSerie)(capitalizationChart.Series.Add(sheet.Cells["B9:B28"], sheet.Cells["D9:D28"]));
capitalizationData.Header = report.Company.Currency;
sheet.Protection.IsProtected = true;
return package.GetAsByteArray();
}
Во-первых, прежде всего, о том, что мы успешно справились с задачей, а именно, сгенерировали свой первый Excel отчет, поработали со стилями и даже решили пару попутных проблем.
Во-вторых, возможно имеет смысл искать новою работу, но, забегая вперед, я бы с этим не спешил… Если данная публикация наберет 1+ просмотров, то во второй части мы поговорим о том, как можно отделить стилизацию от логики заполнения данными, упростить манипуляции над ячейками и в целом сделаем код боле поддерживаемым.
Introduction
No one can deny that «Export to Excel» will forever be a hot topic for both programmers and developers. There are even many articles related to it but we are still often frustrated when we encounter problems. In this article, I will introduce a few solutions based on special Export to Excel questions that are frequently asked by people in forums.
Content Table
- Export One Datatable to One Excel Sheet
- Export multiple Datatables to multiple Excel Sheets
- Export multiple Datatables to One Excel Sheet
- Export Specific Rows and Columns to Excel Sheet
Export One Datatable from Database to One Excel Sheet
Although exporting one datatable to one Excel sheet does not deserve a special topic, it is the most common one. After viewing all the following solutions, you may find how helpful this solution is. In this solution, I use this .NET Excel component Spire.XLS for .NET which is a third party library. Using it, we do not need to install Microsoft Excel. Now let us start our task.
Connect with Database
We all know that the first step to export a database table to Excel is to connect with the database (I use a Microsoft Access database). At the very beginning, we need to represent an open connection to the data source by initializing a new instance of this class System.Data.OleDb.OleDbConnection. Then, open the database by the string OldBdConnection.ConnectionString. After that, we can use the CommandText property of the class System.Data.OleDb.OleDbCommand to state a certain datatable. To get the datatable data and fill the data in the dataset table, we need to call the method System.Data.OleDb.OleDbDataAdapter.Fill(DataSet dataSet). Here you can see the code:
OleDbConnection connection = new OleDbConnection();
connection.ConnectionString = @"Provider=""Microsoft.Jet.OLEDB.4.0"";Data Source=""demo.mdb"";User Id=;Password=";
OleDbCommand command = new OleDbCommand();
command.CommandText = "select * from parts";
using (OleDbDataAdapter dataAdapter = new OleDbDataAdapter(command.CommandText, connection))
{
DataTable t = new DataTable();
dataAdapter.Fill(t);
}
If you use SQL database, you need connect database with following code:
SqlConnection connection = new SqlConnection();
connection.ConnectionString = @"Data Source=server;Initial Catalog=db;User ID=test;Password=test;";
SqlCommand command = new SqlCommand();
command.CommandText = "select * from parts";
using (SqlDataAdapter dataAdapter = new SqlDataAdapter(command.CommandText, connection))
{
DataTable t = new DataTable();
dataAdapter.Fill(t);
}
Export to Excel
When using Spire.XLS, we can export a datatable to Excel by only one method, which is:
Spire.Xls.Worksheet.InsertDataColumn(DataColumn dataColumn, bool columnHeaders, int firstRow, int firstColumn);
There are four parameters passed. The first one is the data column to import. The second indicates whether to import field names. The last two decide the start row and column in Excel when the datatable data is exported to the worksheet.
Workbook book = new Workbook();
Worksheet sheet = book.Worksheets[0];
sheet.InsertDataTable(t, true, 1, 1);
book.SaveToFile("ToExcel.xls");
Export multiple Datatables to multiple Excel Sheets from Database
After knowing how to export one datatable to an Excel sheet, I can say that exporting multiple datatables to Excel sheets is just a piece of cake. The main method is the same as the method called in the solution above; it is:
Spire.Xls.Worksheet.InsertDataColumn(DataColumn dataColumn, bool columnHeaders, int firstRow, int firstColumn);
The only difference is that in this solution we need to export more than one datatable to Excel sheets. Please see the detailed code:
static void Main(string[] args)
{
Workbook workbook = new Workbook();
DataTable dt = GetDataTableFromDB("select * from country");
workbook.Worksheets[0].InsertDataTable(dt, true, 1, 1);
dt = GetDataTableFromDB("select * from items");
workbook.Worksheets[1].InsertDataTable(dt, true, 1, 1);
dt = GetDataTableFromDB("select * from parts");
workbook.Worksheets[2].InsertDataTable(dt, true, 1, 1);
workbook.SaveToFile("sample.xlsx", ExcelVersion.Version2010);
System.Diagnostics.Process.Start("sample.xlsx");
}
static DataTable GetDataTableFromDB(string cmdText)
{
DataTable dt = new DataTable();
string connStr="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=demo.mdb";
using (OleDbConnection conn = new OleDbConnection(connStr))
{
OleDbCommand commd = new OleDbCommand(cmdText,conn);
using (OleDbDataAdapter da = new OleDbDataAdapter(commd))
{
da.Fill(dt);
}
}
return dt;
}
Export multiple Datatables to One Excel Sheet from a Database
When we export multiple datatables to one Excel sheet, we should return to the following method again:
Spire.Xls.Worksheet.InsertDataColumn(DataColumn dataColumn, bool columnHeaders, int firstRow, int firstColumn);
As I said above, the last two parameters specify the start row and column in Excel when we export the datatable data to a worksheet. By specifying the two parameters, we can export multiple datatables to one Excel sheet. Of course, we should be very clear about which cell is the start cell and which is the end cell of each datatable when exporting to Excel.
Export Specific Rows and Columns from Datatable to Excel Sheet
In this solution, I would like to create a Windows Forms project. Thus, we can read the datatable in DataGridView clearly and quickly decide which rows and columns should be exported to Excel. The following is a picture of my datatable data which is completely shown in a DataGridView:
Now, I want to export data that is less than 1000 in the «Cost» column and the data that is greater than 500 in the «ListPrice» column to Excel. Let us use this CommandText property of the class System.Data.OleDb.OleDbCommand to directly state certain conditions that the data must satisfy from a specific datatable. Then, export this data to a DataSet table and DataGridView. Finally export the DataGridView data to Excel. Please see the entire code below:
private void button1_Click(object sender, EventArgs e)
{
//connect with database
OleDbConnection connection = new OleDbConnection();
connection.ConnectionString = @"Provider=""Microsoft.Jet.OLEDB.4.0"";Data Source=""demo.mdb"";User Id=;Password=";
OleDbCommand command = new OleDbCommand();
command.CommandText = "select * from parts where Cost<1000 and ListPrice>500";
DataSet dataSet = new System.Data.DataSet();
OleDbDataAdapter dataAdapter = new OleDbDataAdapter(command.CommandText, connection);
dataAdapter.Fill(dataSet);
DataTable dt = dataSet.Tables[0];
this.dataGridView1.DataSource = dt;
//export specific data to Excel
Workbook book = new Workbook();
Worksheet sheet = book.Worksheets[0];
book.Worksheets[0].InsertDataTable(this.dataGridView1.DataSource as DataTable, true, 1, 1);
book.SaveToFile("sample.xlsx", ExcelVersion.Version2010);
System.Diagnostics.Process.Start("sample.xlsx");
}
Here you can see the effect in the DataGridView that is the same with the target Excel file:
Conclusion
After reading all the solutions, we can easily find that these solutions are very similar to the others except for a little difference. Most people know how to export data from a database to Excel, while how many people have tried exporting multiple datatables or specific rows and columns to Excel? Sometimes, the answer is around us but we do not find them. If we can draw differences about other cases from one basic instance, things will be much easier.
|
HellsingOva 19 / 20 / 8 Регистрация: 27.11.2010 Сообщений: 323 |
||||||||
|
1 |
||||||||
|
06.11.2012, 00:26. Показов 20903. Ответов 9 Метки нет (Все метки)
У меня есть таблица которая получается путем вывода из базы данных sql server
эту таблицу нужно записать в файл exel пробовал подключать Microsoft.Office.Interop.Excel.dll и Microsoft.Office.Interop.Word.dll Добавлено через 1 час 42 минуты
так и не понял он сохраняет файл всегда в папке C:UsersuserDocuments как указать имя файла и путь сохранения
0 |
|
Programming Эксперт 94731 / 64177 / 26122 Регистрация: 12.04.2006 Сообщений: 116,782 |
06.11.2012, 00:26 |
|
9 |
|
Eva_yk 45 / 45 / 18 Регистрация: 15.03.2009 Сообщений: 178 |
||||||||||||||||
|
06.11.2012, 07:02 |
2 |
|||||||||||||||
|
Вместо:
напиши полный путь к файлу, куда сохранять
Ну и вместо:
0 |
|
HellsingOva 19 / 20 / 8 Регистрация: 27.11.2010 Сообщений: 323 |
||||||||
|
06.11.2012, 22:38 [ТС] |
3 |
|||||||
|
заменил на
и
сохраняет не на диске д а в документах под именем книга 1 при 2 клике на кнопку с укаазанием 2 имени спрашивает заменить книгу 1 да нет отмена
0 |
|
HellsingOva 19 / 20 / 8 Регистрация: 27.11.2010 Сообщений: 323 |
||||||||
|
07.11.2012, 23:32 [ТС] |
4 |
|||||||
|
Если кому интересно вот полностью рабочая функция записывающая файл ехел для начала подключаем ссылки и объявляем в начале кода
думаю с подключением ссылок не будет проблем для тех кто не догадался ссылки: а вот собственно сам класс
2 |
|
VoltDeMar 18 / 18 / 4 Регистрация: 05.06.2012 Сообщений: 1,020 |
||||||||
|
13.05.2013, 17:09 |
5 |
|||||||
|
Если кому интересно вот полностью рабочая функция записывающая файл ехел для начала подключаем ссылки и объявляем в начале кода
думаю с подключением ссылок не будет проблем для тех кто не догадался ссылки: а вот собственно сам класс
Столкнулся с той же задачей, можно по подробнее про то что нужно подключать и как это сделать
0 |
|
19 / 20 / 8 Регистрация: 27.11.2010 Сообщений: 323 |
|
|
13.05.2013, 18:30 [ТС] |
6 |
|
Столкнулся с той же задачей, можно по подробнее про то что нужно подключать и как это сделать Нажимаешь проект -> добавить ссылку находишь в списке Кнопка добавить Потом подключаешь их
1 |
|
18 / 18 / 4 Регистрация: 05.06.2012 Сообщений: 1,020 |
|
|
20.05.2013, 09:21 |
7 |
|
Нажимаешь проект -> добавить ссылку находишь в списке Кнопка добавить Потом подключаешь их Выдает ошибку на виндовс 7 — ошибка виндовс ( прекращена работа Excel ), на виндовс 8 помимо этого catch (Exception) еще ловит : System.Runtime.InteropServices.COMException (0x800A03EC): Приложению Microsoft Excel не удается получить доступ к файлу «D:Отчет за 20.5.2013.xlsx». Это может быть вызвано одной из следующих причин. • Указан несуществующий файл или путь. Насчёт несуществующего файла вообще то он прав. Может ещё что то сделать нужно?
0 |
|
19 / 20 / 8 Регистрация: 27.11.2010 Сообщений: 323 |
|
|
20.05.2013, 09:49 [ТС] |
8 |
|
Столкнулся с той же задачей, можно по подробнее про то что нужно подключать и как это сделать попробуй подключить
0 |
|
18 / 18 / 4 Регистрация: 05.06.2012 Сообщений: 1,020 |
|
|
20.05.2013, 10:24 |
9 |
|
попробуй подключить Не нашел такого в списке ссылок, может рабочей сборкой поделитесь?
0 |
On Windows you can use ODBC, which allow working with Excel sheets as regular database tables. It only deals with data though, not formatting, diagrams etc. Standard ODBC driver supports only xls files; to create xlsx file Microsoft Access 2010+ Database Engine Redistributable must be installed.
Example:
#include <stdio.h>
#include <tchar.h>
#include <locale.h>
#include <Windows.h>
#include <sqlext.h>
WCHAR szDSN[] = L"Driver={Microsoft Excel Driver (*.xls)};DSN='';CREATE_DB="C:\test\newfile.xls";DBQ=C:\test\newfile.xls;READONLY=0;";
BOOL ExecuteSql(HDBC hDbc, LPWSTR query){
RETCODE rc;
HSTMT hStmt;
WCHAR bufstate[10]=L"";
WCHAR buferr[1024]=L"";
SQLINTEGER i;
SQLSMALLINT cch;
BOOL result;
wprintf(L">%sn", query);
/* Prepare SQL query */
rc = SQLAllocStmt(hDbc,&hStmt);
if(!SQL_SUCCEEDED(rc)){
wprintf(L"SQLAllocStmt failedn");
return FALSE;
}
rc = SQLPrepare(hStmt, query, SQL_NTS);
if(!SQL_SUCCEEDED(rc)){
wprintf(L"SQLPrepare failedn");
SQLFreeHandle(SQL_HANDLE_STMT,hStmt);
return FALSE;
}
/* Excecute the query */
rc = SQLExecute(hStmt);
if (SQL_SUCCEEDED(rc)) {
wprintf(L"SQL Successn");
result = TRUE;
}
else{
SQLGetDiagRec(SQL_HANDLE_STMT,hStmt,1,bufstate,&i,buferr,sizeof(buferr)/sizeof(buferr[0]),&cch);
wprintf(L"SQL Error. Code: %d; Message: %sn",i,buferr);
result = FALSE;
}
SQLFreeHandle(SQL_HANDLE_STMT,hStmt);
return result;
}
int _tmain(int argc, _TCHAR* argv[])
{
setlocale(LC_ALL,"Russian");
HENV hEnv;
HDBC hDbc;
/* ODBC API return status */
RETCODE rc;
int iConnStrLength2Ptr;
WCHAR szConnStrOut[256];
/* Allocate an environment handle */
rc = SQLAllocEnv(&hEnv);
/* Allocate a connection handle */
rc = SQLAllocConnect(hEnv, &hDbc);
/* Connect to the database */
rc = SQLDriverConnect(hDbc, NULL, (WCHAR*)szDSN,
SQL_NTS, (WCHAR*)szConnStrOut,
255, (SQLSMALLINT*)&iConnStrLength2Ptr, SQL_DRIVER_NOPROMPT);
if (SQL_SUCCEEDED(rc))
{
wprintf(L"Successfully connected to database. Data source name: n %sn",
szConnStrOut);
ExecuteSql(hDbc,L"CREATE TABLE [Test] ([Name] TEXT, [Surname] TEXT)");
ExecuteSql(hDbc,L"INSERT INTO [Test] VALUES ('John','Smith')");
}
else
{
wprintf(L"Couldn't connect to %s.n",szDSN);
}
/* Disconnect and free up allocated handles */
SQLDisconnect(hDbc);
SQLFreeHandle(SQL_HANDLE_DBC, hDbc);
SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
getchar();
return 0;
}
- Download CreateExcelFile.zip — 10Kb
Introduction
I first published this CodeProject article, describing my «Export to Excel» C# library, back in 2014, and it’s still hugely popular today.
So, in this article, I’ll bring it right up to date, and show you how to use the library in a regular C# app, an ASP.NET app, and an ASP.NET Core 2+ app.
In a nutshell, my library lets you add an «export to Excel» function to your C# app, just by using some free Microsoft libraries, my class, and one line of code. Simply tell my library where your DataSet, DataTable, or List<> data is stored, and what (Excel) filename you want to write to.
Here’s how you would use it in a C# WinForms app:
DataSet ds = CreateSampleData(); try { string excelFilename = "C:\Sample.xlsx"; CreateExcelFile.CreateExcelDocument(ds, excelFilename); } catch (Exception ex) { MessageBox.Show("Couldn't create Excel file.rnException: " + ex.Message); return; }
Limitations
Don’t get me wrong — this C# library is absolutely bare-bones. If you’re looking for a library where you can export things like images, diagrams, and pivot tables to an Excel file, then this isn’t the right place for you. You can either go and buy a third-party library, or take the code which I’ve provided, and use it as a basis to create your own customized library.
As you’ll see, this C# library simply takes a chunk of data stored in a DataSet, DataTable, or List<>, and outputs it to an Excel .xlsx file. Oh, and it will create one worksheet per DataTable in your DataSet.
A few nice things about this library though:
- It will look at your types of data, and attempt to set the correct Excel cell styles. For example, if you have a
DateTimecolumn, it will write your data value to the Excel file as a number, and apply a style to show it as a date. This is how Excel stores such data itself. - Because the Excel file is created using Microsoft’s free OpenXML library, you can run this code on machines which don’t have Excel installed.
- My library creates the file using
OpenXmlWriter. This has a huge advantage that, when you’re creating massive Excel files, it won’t wait until it has created all of the elements for your Excel file before writing it all out to the file. Without this functionality, you would be receiving out-of-memory errors when trying to create large Excel files. - On each worksheet, I set the header text to a different style. You can look at the
GenerateStyleSheet()function in my library to see how I’ve done this, and feel free to customize its apparence, fonts and colors, as desired.
Having said all of that, this C# library is golden. I’ve spent the last 12 years working in financial companies in Zurich, and, without exception, no matter how beautiful and responsive you make your application, the users always want the possibility to play around with the data using Excel. And now, you can slip in this functionality without breaking a sweat.
1. Adding the library to your ASP.NET Core 2+ application
Let’s start with ASP.NET Core, as this is where most of you should/will be using. There are three very easy steps to adding my library to your application.
First, download the CreateExcelFile.cs file from the top of this article, and add it to your project. At the top of this file, you’ll see three commented-out #define statements. You need to just uncomment the second one, to say you’re using ASP.NET Core:
#define USING_ASP_NET_CORE // Uncomment this line, if you're using ASP.NET Core 2 or later
Next, you need to open «NuGet Package Manager» in Visual Studio and include the «DocumentFormat.OpenXml» nuget package. This is Microsoft’s library for creating Excel files.
And finally, you need to get your code to call the StreamExcelDocument function. I actually demonstrate how to do this from an ASP.Net Core Web API in this CodeProject article.
[HttpGet("ExportToExcel")] public async Task<IActionResult> ExportEmployeesToExcel() { try { List<Employee> employees = await _context.Employee.ToListAsync(); FileStreamResult fr = ExportToExcel.CreateExcelFile.StreamExcelDocument (employees, "Employees.xlsx"); return fr; } catch (Exception ex) { return new BadRequestObjectResult(ex); } }
How simple that that ! You basically pass it a List, give it a filename, then my library creates the Excel file for you, and passes it back in a FileStreamResult object.
2. Adding the library to your ASP.NET application
If you’re still using the original ASP.NET (and if so, why?!), then here are the steps to use the library in your application.
First, you need to include the System.Web library in your project…
… and then uncomment the first using statement at the top of my CreateExcelFile.cs file:
#define USING_ASP_NET // Uncomment this line, if you're using the old ASP.NET
Next, you’ll need to download and install the free Microsoft OpenXML SDK from here: Microsoft OpenXML SDK download. (Note: if this link changes, simply Google for «Microsoft OpenXML download«.
You actually only need two files from this SDK:
- DocumentFormat.OpenXml.dll
- WindowsBase.dll
Add each of these .dlls to your project’s References section, and remember to set them to «Copy Local».
Using ASP.NET (not ASP.NET Core), you have access to three functions, for creating your Excel files.
public static bool CreateExcelDocument<T>(List<T> list, string filename, System.Web.HttpResponse Response) public static bool CreateExcelDocument(DataTable dt, string filename, System.Web.HttpResponse Response) public static bool CreateExcelDocument(DataSet ds, string filename, System.Web.HttpResponse Response)
For example, if my ASP.NET C# application had a list of employee records, stored in a List<Employee>, then I would add an «Export to Excel» button to my webpage, and when the user clicks on it, I just need one simple call to the CreateExcelFile class.
List<Employee> listOfEmployees = new List<Employee>(); ... protected void btnExportToExcel_Click(object sender, EventArgs e) { CreateExcelFile.CreateExcelDocument(listOfEmployees, "Employees.xlsx", Response); }
3. Adding the library to your C# WinForms application
This is almost the same steps as for ASP.NET (above). Once again, you need to download and install the free Microsoft OpenXML SDK using the link above, and include the two .dlls in your project.
Then just include my CreateExcelFile.cs file in your project, and you’re good to go. Just get your data into a DataSet, DataTable, or List<> variable and call the CreateExcelDocument function, with a filename to save to.
DataSet ds = CreateSampleData(); CreateExcelFile.CreateExcelDocument(ds, "C:\Sample.xlsx");
And that’s it.
Going forward
As I said, this C# library is amazing, but won’t fill everyone’s criteria. However, it is an excellent starting point for adding your own functionality. For example, if you wanted to add a background color to some of the cells in the Excel file, simply Google «open xml background color» and you’ll have many articles showing you how to do this.
The reason I wrote this article is that I found that it was very hard to find a free, easy to use C# library which actually created the OpenXML Excel file in the first place.
Good luck, and don’t forget to rate this article if you like it, and leave a comment with any questions.





)

