Npoi c примеры excel

Существует хорошая библиотека для Java Apache POI — the Java API for Microsoft Documents http://poi.apache.org/, которая позволяет работать с документами Microsoft. Была создана портация этой библиотеки на C# и называется она NPOI http://npoi.codeplex.com/. В данной заметке будет описан пример использования NPOI.

Для получения библиотеки идём на сайт https://npoi.codeplex.com/ переходим в раздел Downloads и скачиваем последнюю версию, на момент написания заметки это 2.1.3.1. Разархивируем архив папку с библиотеками. 

В архиве есть библиотеки для версии Net 4.0 и Net 2.0. 

Теперь создаём тестовый проект в VisulaStudio. Назовём его к примеру TestNPOI.

Добавим на форму 2 текстовых окна для добавления файлов и две кнопки.

В Referens проекта добавим скачанные библиотеки, в моём случае я добавлял библиотеки для Net 4.0.

Напишем код для сохранения файла в Excel в формат xlsx. К нашему модулю нужно подключить стандартные модули и два модуля using NPOI.SS.UserModel; и NPOI NPOI.XSSF.UserModel:

using System.IO;
using System.Windows;
using System.Diagnostics;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;

Теперь напишем код по выгрузке данных в Excel файл.

private void bSaveFile_Click(object sender, RoutedEventArgs e)
        {
            //Рабочая книга Excel
            XSSFWorkbook wb;
            //Лист в книге Excel
            XSSFSheet sh;

            //Создаем рабочую книгу
            wb = new XSSFWorkbook();
            //Создаём лист в книге
            sh = (XSSFSheet)wb.CreateSheet("Лист 1");

            //Количество заполняемых строк
            int countRow = 3;
            //Количество заполняемых столбцов
            int countColumn = 3;

            //Запускаем цыкл по строка
            for (int i = 0; i < countRow; i++)
            {
                //Создаем строку
                var currentRow = sh.CreateRow(i);

                //Запускаем цикл по столбцам
                for (int j = 0; j < countColumn; j++)
                {
                    //в строке создаём ячеёку с указанием столбца
                    var currentCell = currentRow.CreateCell(j);
                    //в ячейку запишем информацию о текущем столбце и строке
                    currentCell.SetCellValue("Строка - "+(i+1).ToString()+"Столбец - "+(j+1).ToString());
                    //Выравним размер столбца по содержимому
                    sh.AutoSizeColumn(j);
                 }
                
            }

            // Удалим файл если он есть уже
            if (!File.Exists(tbSaveFile.Text))
            {
                File.Delete(tbSaveFile.Text);
            }

            //запишем всё в файл
            using (var fs = new FileStream(tbSaveFile.Text, FileMode.Create, FileAccess.Write))
            {
                wb.Write(fs);
            }

            //Откроем файл
            Process.Start(tbSaveFile.Text);

        }

В результате получи следующий файл

Теперь сохраним этот файл в TestLoad.xlsx и напишем код по чтению данных из файла.

private void bLoadFile_Click(object sender, RoutedEventArgs e)
        {
            //Книга Excel
            XSSFWorkbook xssfwb;

            //Открываем файл
            using (FileStream file = new FileStream(tbLoadFile.Text, FileMode.Open, FileAccess.Read))
            {
                xssfwb = new XSSFWorkbook(file);
            }
            //Получаем первый лист книги
            ISheet sheet = xssfwb.GetSheetAt(0);

            //запускаем цикл по строкам
            for (int row = 0; row <= sheet.LastRowNum; row++)
            {
                //получаем строку
                var currentRow = sheet.GetRow(row);
                if (currentRow != null) //null когда строка содержит только пустые ячейки
                {
                    //запускаем цикл по столбцам
                    for (int column = 0; column < 3; column++)
                    {
                        //получаем значение яейки
                        var stringCellValue = currentRow.GetCell(column).StringCellValue;
                        //Выводим сообщение
                        MessageBox.Show(string.Format("Ячейка {0}-{1} значение:{2}", row,column,stringCellValue));
                    }
                }
            }
        }

NPOI Examples

This repository is splitted from NPOI master repository in order to manage the examples easily.

About Donation

Since Github sponsorship is not supported in China so far, it’s hard to get donation from Github channel. I’m strictly limiting my contribution time on NPOI these 2 years although it looks to be still maintained well. If you profits/benefits from NPOI and you believe it’s useful, please donate this project. Thank you!

Telegram User Group

Join us on telegram: https://t.me/npoidevs

To Get Started with NPOI (on Windows 10)

  1. Open PowerShell and run the following command:
git clone https://github.com/nissl-lab/npoi-examples
  1. Open npoi-examples/ss/CalendarDemo/CalendarDemo.csproj with Visual Studio 2019 community version and click ‘Run program’ button
  2. You will see a new generated file called Calendar.xls under npoi-examples/ss/CalendarDemo/bin/Debug folder
  3. Open the Calendar.xls with Microsoft Excel or Kingsoft WPS
  4. Go back to Powershell window and run the following command
cd npoi-examples/ss/CalendarDemo/bin/Debug
./CalendarDemo -xlsx 
  1. You will see a new generated file called Calendar.xlsx under npoi-examples/ss/CalendarDemo/bin/Debug folder
  2. Open the Calendar.xlsx with Microsoft Excel or Kingsoft WPS

Conclusion: The result of Calendar.xls and Calendar.xlsx looks same in Microsoft Excel or Kingsoft WPS but they are totally different file formats generated by NPOI.

Folders Explained

Folder Name Description
POIFS OLE2/ActiveX document examples
HSSF examples for Microsoft Excel BIFF(Excel 97-2003, xls)
SS Excel Common examples for both Excel 2003(xls) and Excel 2007+(xlsx)
XSSF Excel 2007(xlsx) examples
XWPF Word 2007(docx) examples
OOXML OpenXml format low-level examples
ScratchPad/HWPF Word 2003(doc) examples

Analytics

I find NPOI very usefull for working with Excel Files, here is my implementation (Comments are in Spanish, sorry for that):

This Method Opens an Excel (both xls or xlsx) file and converts it into a DataTable.

        /// <summary>Abre un archivo de Excel (xls o xlsx) y lo convierte en un DataTable.
    /// LA PRIMERA FILA DEBE CONTENER LOS NOMBRES DE LOS CAMPOS.</summary>
    /// <param name="pRutaArchivo">Ruta completa del archivo a abrir.</param>
    /// <param name="pHojaIndex">Número (basado en cero) de la hoja que se desea abrir. 0 es la primera hoja.</param>
    private DataTable Excel_To_DataTable(string pRutaArchivo, int pHojaIndex)
    {
        // --------------------------------- //
        /* REFERENCIAS:
         * NPOI.dll
         * NPOI.OOXML.dll
         * NPOI.OpenXml4Net.dll */
        // --------------------------------- //
        /* USING:
         * using NPOI.SS.UserModel;
         * using NPOI.HSSF.UserModel;
         * using NPOI.XSSF.UserModel; */
        // AUTOR: Ing. Jhollman Chacon R. 2015
        // --------------------------------- //
        DataTable Tabla = null;
        try
        {
            if (System.IO.File.Exists(pRutaArchivo))
            {

                IWorkbook workbook = null;  //IWorkbook determina si es xls o xlsx              
                ISheet worksheet = null;
                string first_sheet_name = "";

                using (FileStream FS = new FileStream(pRutaArchivo, FileMode.Open, FileAccess.Read))
                {
                    workbook = WorkbookFactory.Create(FS);          //Abre tanto XLS como XLSX
                    worksheet = workbook.GetSheetAt(pHojaIndex);    //Obtener Hoja por indice
                    first_sheet_name = worksheet.SheetName;         //Obtener el nombre de la Hoja

                    Tabla = new DataTable(first_sheet_name);
                    Tabla.Rows.Clear();
                    Tabla.Columns.Clear();

                    // Leer Fila por fila desde la primera
                    for (int rowIndex = 0; rowIndex <= worksheet.LastRowNum; rowIndex++)
                    {
                        DataRow NewReg = null;
                        IRow row = worksheet.GetRow(rowIndex);
                        IRow row2 = null;
                        IRow row3 = null;

                        if (rowIndex == 0)
                        {
                            row2 = worksheet.GetRow(rowIndex + 1); //Si es la Primera fila, obtengo tambien la segunda para saber el tipo de datos
                            row3 = worksheet.GetRow(rowIndex + 2); //Y la tercera tambien por las dudas
                        }

                        if (row != null) //null is when the row only contains empty cells 
                        {
                            if (rowIndex > 0) NewReg = Tabla.NewRow();

                            int colIndex = 0;
                            //Leer cada Columna de la fila
                            foreach (ICell cell in row.Cells)
                            {
                                object valorCell = null;
                                string cellType = "";
                                string[] cellType2 = new string[2];

                                if (rowIndex == 0) //Asumo que la primera fila contiene los titlos:
                                {
                                    for (int i = 0; i < 2; i++)
                                    {
                                        ICell cell2 = null;
                                        if (i == 0) { cell2 = row2.GetCell(cell.ColumnIndex); }
                                        else { cell2 = row3.GetCell(cell.ColumnIndex); }

                                        if (cell2 != null)
                                        {
                                            switch (cell2.CellType)
                                            {
                                                case CellType.Blank: break;
                                                case CellType.Boolean: cellType2[i] = "System.Boolean"; break;
                                                case CellType.String: cellType2[i] = "System.String"; break;
                                                case CellType.Numeric:
                                                    if (HSSFDateUtil.IsCellDateFormatted(cell2)) { cellType2[i] = "System.DateTime"; }
                                                    else
                                                    {
                                                        cellType2[i] = "System.Double";  //valorCell = cell2.NumericCellValue;
                                                    }
                                                    break;

                                                case CellType.Formula:                                                      
                                                    bool continuar = true;
                                                    switch (cell2.CachedFormulaResultType)
                                                    {
                                                        case CellType.Boolean: cellType2[i] = "System.Boolean"; break;
                                                        case CellType.String: cellType2[i] = "System.String"; break;
                                                        case CellType.Numeric:
                                                            if (HSSFDateUtil.IsCellDateFormatted(cell2)) { cellType2[i] = "System.DateTime"; }
                                                            else
                                                            {
                                                                try
                                                                {
                                                                    //DETERMINAR SI ES BOOLEANO
                                                                    if (cell2.CellFormula == "TRUE()") { cellType2[i] = "System.Boolean"; continuar = false; }
                                                                    if (continuar && cell2.CellFormula == "FALSE()") { cellType2[i] = "System.Boolean"; continuar = false; }
                                                                    if (continuar) { cellType2[i] = "System.Double"; continuar = false; }
                                                                }
                                                                catch { }
                                                            } break;
                                                    }
                                                    break;
                                                default:
                                                    cellType2[i] = "System.String"; break;
                                            }
                                        }
                                    }

                                    //Resolver las diferencias de Tipos
                                    if (cellType2[0] == cellType2[1]) { cellType = cellType2[0]; }
                                    else
                                    {
                                        if (cellType2[0] == null) cellType = cellType2[1];
                                        if (cellType2[1] == null) cellType = cellType2[0];
                                        if (cellType == "") cellType = "System.String";
                                    }

                                    //Obtener el nombre de la Columna
                                    string colName = "Column_{0}";
                                    try { colName = cell.StringCellValue; }
                                    catch { colName = string.Format(colName, colIndex); }

                                    //Verificar que NO se repita el Nombre de la Columna
                                    foreach (DataColumn col in Tabla.Columns)
                                    {
                                        if (col.ColumnName == colName) colName = string.Format("{0}_{1}", colName, colIndex);
                                    }

                                    //Agregar el campos de la tabla:
                                    DataColumn codigo = new DataColumn(colName, System.Type.GetType(cellType));
                                    Tabla.Columns.Add(codigo); colIndex++;
                                }
                                else
                                {
                                    //Las demas filas son registros:
                                    switch (cell.CellType)
                                    {
                                        case CellType.Blank: valorCell = DBNull.Value; break;
                                        case CellType.Boolean: valorCell = cell.BooleanCellValue; break;
                                        case CellType.String: valorCell = cell.StringCellValue; break;
                                        case CellType.Numeric:
                                            if (HSSFDateUtil.IsCellDateFormatted(cell)) { valorCell = cell.DateCellValue; }
                                            else { valorCell = cell.NumericCellValue; } break;
                                        case CellType.Formula:
                                            switch (cell.CachedFormulaResultType)
                                            {
                                                case CellType.Blank: valorCell = DBNull.Value; break;
                                                case CellType.String: valorCell = cell.StringCellValue; break;
                                                case CellType.Boolean: valorCell = cell.BooleanCellValue; break;
                                                case CellType.Numeric:
                                                    if (HSSFDateUtil.IsCellDateFormatted(cell)) { valorCell = cell.DateCellValue; }
                                                    else { valorCell = cell.NumericCellValue; }
                                                    break;
                                            }
                                            break;
                                        default: valorCell = cell.StringCellValue; break;
                                    }
                                    //Agregar el nuevo Registro
                                    if (cell.ColumnIndex <= Tabla.Columns.Count - 1) NewReg[cell.ColumnIndex] = valorCell;
                                }
                            }
                        }
                        if (rowIndex > 0) Tabla.Rows.Add(NewReg);
                    }
                    Tabla.AcceptChanges();
                }
            }
            else
            {
                throw new Exception("ERROR 404: El archivo especificado NO existe.");
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
        return Tabla;
    }

This Second method does the oposite, saves a DataTable into an Excel File, yeah it can either be xls or the new xlsx, your choise!

        /// <summary>Convierte un DataTable en un archivo de Excel (xls o Xlsx) y lo guarda en disco.</summary>
    /// <param name="pDatos">Datos de la Tabla a guardar. Usa el nombre de la tabla como nombre de la Hoja</param>
    /// <param name="pFilePath">Ruta del archivo donde se guarda.</param>
    private void DataTable_To_Excel(DataTable pDatos, string pFilePath)
    {
        try
        {
            if (pDatos != null && pDatos.Rows.Count > 0)
            {
                IWorkbook workbook = null;
                ISheet worksheet = null;

                using (FileStream stream = new FileStream(pFilePath, FileMode.Create, FileAccess.ReadWrite))
                {
                    string Ext = System.IO.Path.GetExtension(pFilePath); //<-Extension del archivo
                    switch (Ext.ToLower())
                    {
                        case ".xls":
                            HSSFWorkbook workbookH = new HSSFWorkbook();
                            NPOI.HPSF.DocumentSummaryInformation dsi = NPOI.HPSF.PropertySetFactory.CreateDocumentSummaryInformation();
                            dsi.Company = "Cutcsa"; dsi.Manager = "Departamento Informatico";
                            workbookH.DocumentSummaryInformation = dsi;
                            workbook = workbookH;
                            break;

                        case ".xlsx": workbook = new XSSFWorkbook(); break;
                    }

                    worksheet = workbook.CreateSheet(pDatos.TableName); //<-Usa el nombre de la tabla como nombre de la Hoja

                    //CREAR EN LA PRIMERA FILA LOS TITULOS DE LAS COLUMNAS
                    int iRow = 0;
                    if (pDatos.Columns.Count > 0)
                    {
                        int iCol = 0;
                        IRow fila = worksheet.CreateRow(iRow);
                        foreach (DataColumn columna in pDatos.Columns)
                        {
                            ICell cell = fila.CreateCell(iCol, CellType.String);
                            cell.SetCellValue(columna.ColumnName);
                            iCol++;
                        }
                        iRow++;
                    }

                    //FORMATOS PARA CIERTOS TIPOS DE DATOS
                    ICellStyle _doubleCellStyle = workbook.CreateCellStyle();
                    _doubleCellStyle.DataFormat = workbook.CreateDataFormat().GetFormat("#,##0.###");

                    ICellStyle _intCellStyle = workbook.CreateCellStyle();
                    _intCellStyle.DataFormat = workbook.CreateDataFormat().GetFormat("#,##0");

                    ICellStyle _boolCellStyle = workbook.CreateCellStyle();
                    _boolCellStyle.DataFormat = workbook.CreateDataFormat().GetFormat("BOOLEAN");

                    ICellStyle _dateCellStyle = workbook.CreateCellStyle();
                    _dateCellStyle.DataFormat = workbook.CreateDataFormat().GetFormat("dd-MM-yyyy");

                    ICellStyle _dateTimeCellStyle = workbook.CreateCellStyle();
                    _dateTimeCellStyle.DataFormat = workbook.CreateDataFormat().GetFormat("dd-MM-yyyy HH:mm:ss");

                    //AHORA CREAR UNA FILA POR CADA REGISTRO DE LA TABLA
                    foreach (DataRow row in pDatos.Rows)
                    {
                        IRow fila = worksheet.CreateRow(iRow);
                        int iCol = 0;
                        foreach (DataColumn column in pDatos.Columns)
                        {
                            ICell cell = null; //<-Representa la celda actual                               
                            object cellValue = row[iCol]; //<- El valor actual de la celda

                            switch (column.DataType.ToString())
                            {
                                case "System.Boolean":
                                    if (cellValue != DBNull.Value)
                                    {
                                        cell = fila.CreateCell(iCol, CellType.Boolean);

                                        if (Convert.ToBoolean(cellValue)) { cell.SetCellFormula("TRUE()"); }
                                        else { cell.SetCellFormula("FALSE()"); }

                                        cell.CellStyle = _boolCellStyle;
                                    }
                                    break;

                                case "System.String":
                                    if (cellValue != DBNull.Value)
                                    {
                                        cell = fila.CreateCell(iCol, CellType.String);
                                        cell.SetCellValue(Convert.ToString(cellValue));
                                    }
                                    break;

                                case "System.Int32":
                                    if (cellValue != DBNull.Value)
                                    {
                                        cell = fila.CreateCell(iCol, CellType.Numeric);
                                        cell.SetCellValue(Convert.ToInt32(cellValue));
                                        cell.CellStyle = _intCellStyle;
                                    }
                                    break;
                                case "System.Int64":
                                    if (cellValue != DBNull.Value)
                                    {
                                        cell = fila.CreateCell(iCol, CellType.Numeric);
                                        cell.SetCellValue(Convert.ToInt64(cellValue));
                                        cell.CellStyle = _intCellStyle;
                                    }
                                    break;
                                case "System.Decimal":
                                    if (cellValue != DBNull.Value)
                                    {
                                        cell = fila.CreateCell(iCol, CellType.Numeric);
                                        cell.SetCellValue(Convert.ToDouble(cellValue));
                                        cell.CellStyle = _doubleCellStyle;
                                    }
                                    break;
                                case "System.Double":
                                    if (cellValue != DBNull.Value)
                                    {
                                        cell = fila.CreateCell(iCol, CellType.Numeric);
                                        cell.SetCellValue(Convert.ToDouble(cellValue));
                                        cell.CellStyle = _doubleCellStyle;
                                    }
                                    break;

                                case "System.DateTime":
                                    if (cellValue != DBNull.Value)
                                    {
                                        cell = fila.CreateCell(iCol, CellType.Numeric);
                                        cell.SetCellValue(Convert.ToDateTime(cellValue));

                                        //Si No tiene valor de Hora, usar formato dd-MM-yyyy
                                        DateTime cDate = Convert.ToDateTime(cellValue);
                                        if (cDate != null && cDate.Hour > 0) { cell.CellStyle = _dateTimeCellStyle; }
                                        else { cell.CellStyle = _dateCellStyle; }
                                    }
                                    break;
                                default:
                                    break;
                            }
                            iCol++;
                        }
                        iRow++;
                    }

                    workbook.Write(stream);
                    stream.Close();
                }
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

With this 2 methods you can Open an Excel file, load it into a DataTable, do your modifications and save it back into an Excel file.

Hope you guys find this usefull.

M.T

M.T

Posted on Jan 29, 2020



 



 



 



 



 

 

Generating an Excel based on some data-set is one of these tasks that you have to do from time to time as a developer.
Normally, I don’t get much of these scenarios when I have to generate an excel, and when I do, I almost forgetting about how is done partially at least.

So, I’ve decided to document a sample and share it out, as it might help someone out there to refresh the vagueness.

Without further due, here we go:

Obviously, the first step would be installing the NPOI library using NuGet which is straight forward process.

NPOI consist of many namespaces, but for now our focus would be on only two:

using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;

We will need NPOI.HSSF.UserModel to be able to use the HSSFWorkbook,HSSFFont, HSSFCellStyle and others needed objects.
While using NPOI.SS.UserModel; will be used to define ISheet,IRow,ICell and other required objects.

The Logic of creating an excel is simple:

  1. Define a Workbook.
  2. Create a Sheet to the workbook.
  3. Add Rows and Cells to the Sheet.

Now before I dive into creating rows & cells, I’ll just write a function to create a cell for us, so instead of writing

ICell Cell = CurrentRow.CreateCell(CellIndex);
            Cell.SetCellValue(Value);

everytime we need to create a cell, we just create this function:

private void CreateCell(IRow CurrentRow, int CellIndex, string Value, HSSFCellStyle Style)
        {
            ICell Cell = CurrentRow.CreateCell(CellIndex);
            Cell.SetCellValue(Value);
            Cell.CellStyle = Style;
        }

So, creating a cell now is just:

 CreateCell(HeaderRow, CellIndex, "Column Value", CellStyle);

Now, let’s start creating an excel based on defined headers and given data collection.

            HSSFWorkbook workbook = new HSSFWorkbook();
            HSSFFont myFont = (HSSFFont)workbook.CreateFont();
            myFont.FontHeightInPoints = 11;
            myFont.FontName = "Tahoma";


            // Defining a border
            HSSFCellStyle borderedCellStyle = (HSSFCellStyle)workbook.CreateCellStyle();
            borderedCellStyle.SetFont(myFont);
            borderedCellStyle.BorderLeft = BorderStyle.Medium;
            borderedCellStyle.BorderTop = BorderStyle.Medium;
            borderedCellStyle.BorderRight = BorderStyle.Medium;
            borderedCellStyle.BorderBottom = BorderStyle.Medium;
            borderedCellStyle.VerticalAlignment = VerticalAlignment.Center;

            ISheet Sheet = workbook.CreateSheet("Report");
            //Creat The Headers of the excel
            IRow HeaderRow = Sheet.CreateRow(0);

            //Create The Actual Cells
            CreateCell(HeaderRow, 0, "Batch Name", borderedCellStyle);
            CreateCell(HeaderRow, 1, "RuleID", borderedCellStyle);
            CreateCell(HeaderRow, 2, "Rule Type", borderedCellStyle);
            CreateCell(HeaderRow, 3, "Code Message Type", borderedCellStyle);
            CreateCell(HeaderRow, 4, "Severity", borderedCellStyle);

            // This Where the Data row starts from
            int RowIndex = 1;

            //Iteration through some collection
            foreach (BatchErrorReport batchErrorReport in BatchErrorReports)
            {
                //Creating the CurrentDataRow
                IRow CurrentRow = Sheet.CreateRow(RowIndex);
                CreateCell(CurrentRow, 0, batchErrorReport.Name, borderedCellStyle);
                // This will be used to calculate the merge area
                int NumberOfRules = batchErrorReport.Rules.Count;
                if (NumberOfRules > 1)
                {
                    int MergeIndex = (NumberOfRules - 1) + RowIndex;

                //Merging Cells
                    NPOI.SS.Util.CellRangeAddress MergedBatch = new NPOI.SS.Util.CellRangeAddress(RowIndex, MergeIndex, 0, 0);
                    Sheet.AddMergedRegion(MergedBatch);
                }
                int i = 0;
                // Iterate through cub collection
                foreach (BatchDataQuality batchDataQuality in batchErrorReport.Rules)
                {
                    if (i > 0)
                        CurrentRow = Sheet.CreateRow(RowIndex);
                    CreateCell(CurrentRow, 1, batchDataQuality.RuleID, borderedCellStyle);
                    CreateCell(CurrentRow, 2, batchDataQuality.RuleType, borderedCellStyle);
                    CreateCell(CurrentRow, 3, batchDataQuality.CodeMessageType, borderedCellStyle);
                    CreateCell(CurrentRow, 4, batchDataQuality.Severity, borderedCellStyle);
                    RowIndex++;
                    i++;
                }
                RowIndex = NumberOfRules >= 1 ? RowIndex : RowIndex + 1;
            }
          // Auto sized all the affected columns
          int lastColumNum = Sheet.GetRow(0).LastCellNum;
          for (int i = 0; i <= lastColumNum; i++)
          {
              Sheet.AutoSizeColumn(i);
                GC.Collect();
          }
         // Write Excel to disk 
          using (var fileData = new FileStream(Utility.DOCUMENT_PATH + "ReportName.xls", FileMode.Create))
            {
                workbook.Write(fileData);
            }

This would produce something like this:
Alt Text

  • Download sample — 650.6 KB

Introduction

This article will walk you through the generic export to Excel feature which is tried and well tested, using C# in WEB API and by using NPOI.

This article is specific to .NET Framework, whereas, I have tried in .NET Core, it works perfectly fine. So hold on and let’s jump over it.

Before We Begin the Journey

The main concept of this article is to develop generic Excel to export functionality by importing NPOI and add the below explained 2 cs files included in the sample and then jet set go.

Explore the Code

I have created a GitHub repository for you to explore the code with ASP.NET MVC, which is right here:

  • https://github.com/ansaridawood/.NET-Generic-Excel-Export-Sample

Background

We are using NPOI DLL for this export which is free to use, refer to NPOI NuGet for more details.

More often, we need to develop an export to Excel feature in our applications, many of us usually create boring string builder, then convert it to Excel or use Interop or ITextSharp or NPOI or something else to achieve the same result.

All the above-listed ways are absolutely correct in their own context and fine, but what if there could be a way to export to Excel as simple as passing an object and getting the required output, our life would have been easier, isn’t it?

This is what I am going to explain in this article.

Using the Code

First of all, there is a utility function called Export() which simply converts your C# List object to NPOI object and then finally provides to HttpResponseMessage type, which can be used in your WEB API Action.

You need 2 files to achieve it — refer to the solution attached in this article for a better understanding >> ExcelExport folder in Root directory:

  1. AbstractDataExport.cs — contains common code
  2. AbstractDataExportBridge.cs — converts List to NPOI Excel object

What does AbstractDataExport.cs do?

Refer to Export(List exportData, string fileName, string sheetName = DefaultSheetName)

Let’s begin with our first file, AbstractDataExport.cs

Creating a New Excel object — _workbook = new XSSFWorkbook();

  1. Creating a New Excel Sheet object — _sheet = _workbook.CreateSheet(_sheetName);
  2. Invokes WriteData() — explained later
  3. Finally, creating and returning MemoryStream object
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;

namespace GenericExcelExport.ExcelExport
{
    public interface IAbstractDataExport
    {
        HttpResponseMessage Export(List exportData, string fileName, string sheetName);
    }

    public abstract class AbstractDataExport : IAbstractDataExport
    {
        protected string _sheetName;
        protected string _fileName;
        protected List _headers;
        protected List _type;
        protected IWorkbook _workbook;
        protected ISheet _sheet;
        private const string DefaultSheetName = "Sheet1";

        public HttpResponseMessage Export
              (List exportData, string fileName, string sheetName = DefaultSheetName)
        {
            _fileName = fileName;
            _sheetName = sheetName;

            _workbook = new XSSFWorkbook(); 
            _sheet = _workbook.CreateSheet(_sheetName); 

            var headerStyle = _workbook.CreateCellStyle(); 
            var headerFont = _workbook.CreateFont();
            headerFont.IsBold = true;
            headerStyle.SetFont(headerFont);

            WriteData(exportData); 

            
            var header = _sheet.CreateRow(0);
            for (var i = 0; i < _headers.Count; i++)
            {
                var cell = header.CreateCell(i);
                cell.SetCellValue(_headers[i]);
                cell.CellStyle = headerStyle;
                
                
            }

            using (var memoryStream = new MemoryStream()) 
            {
                _workbook.Write(memoryStream);
                var response = new HttpResponseMessage(HttpStatusCode.OK)
                {
                    Content = new ByteArrayContent(memoryStream.ToArray())
                };

                response.Content.Headers.ContentType = new MediaTypeHeaderValue
                       ("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
                response.Content.Headers.ContentDisposition = 
                       new ContentDispositionHeaderValue("attachment")
                {
                    FileName = $"{_fileName}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx"
                };

                return response;
            }
        }

        
        public abstract void WriteData(List exportData);
    }
}

Now, let’s proceed towards our second and final file, i.e., AbstractDataExportBridge.cs. Below is the explanation for WriteData(List exportData):

  1. Converts List to DataTable
  2. Reflection to read property name, your column header will be coming from here
  3. Loop through DataTable to create Excel Rows

There are areas of improvement here, you can make necessary changes like removing DataTable completely.

using NPOI.SS.UserModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Text.RegularExpressions;

namespace GenericExcelExport.ExcelExport
{
    public class AbstractDataExportBridge : AbstractDataExport
    {
        public AbstractDataExportBridge()
        {
            _headers = new List<string>();
            _type = new List<string>();
        }

        public override void WriteData<T>(List<T> exportData)
        {
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));

            DataTable table = new DataTable();

            foreach (PropertyDescriptor prop in properties)
            {
                var type = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
                _type.Add(type.Name);
                table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? 
                                  prop.PropertyType);
                string name = Regex.Replace(prop.Name, "([A-Z])", " $1").Trim();
                
                _headers.Add(name);
            }

            foreach (T item in exportData)
            {
                DataRow row = table.NewRow();
                foreach (PropertyDescriptor prop in properties)
                    row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
                table.Rows.Add(row);
            }

            IRow sheetRow = null;

            for (int i = 0; i < table.Rows.Count; i++)
            {
                sheetRow = _sheet.CreateRow(i + 1);

                for (int j = 0; j < table.Columns.Count; j++)
                {
                    ICell Row1 = sheetRow.CreateCell(j);
                    string cellvalue = Convert.ToString(table.Rows[i][j]);
                    
                    

                    if (string.IsNullOrWhiteSpace(cellvalue))
                    {
                        Row1.SetCellValue(string.Empty);
                    }
                    else if (_type[j].ToLower() == "string")
                    {
                        Row1.SetCellValue(cellvalue);
                    }
                    else if (_type[j].ToLower() == "int32")
                    {
                        Row1.SetCellValue(Convert.ToInt32(table.Rows[i][j]));
                    }
                    else if (_type[j].ToLower() == "double")
                    {
                        Row1.SetCellValue(Convert.ToDouble(table.Rows[i][j]));
                    }
                    else if (_type[j].ToLower() == "datetime")
                    {
                        Row1.SetCellValue(Convert.ToDateTime
                             (table.Rows[i][j]).ToString("dd/MM/yyyy hh:mm:ss"));
                    }
                    else
                    {
                        Row1.SetCellValue(string.Empty);
                    }
                }
            }
        }
    }
}

Points of Interest

I came across this solution when I had over 20 forms to provide Excel export feature, and I wasn’t willing to use a traditional approach which will be lengthy in my case.

There are always areas of improvement in all things. If you see any areas of improvement here, please update in the comments.

History

  • 27th April, 2018: Initial draft
  • 12th August, 2019: Performance improvement based on new findings in my applications

This member has not yet provided a Biography. Assume it’s interesting and varied, and probably something to do with programming.

Понравилась статья? Поделить с друзьями:
  • Nowadays the word business is
  • Nowadays is not a word
  • Nowadays everybody knows what the word america means перевод
  • Now you never say a word
  • Now you never said the word