Formatting and Exporting Structured Excel Files with C# and NPOI

using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.SS.Util;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
public IActionResult GenerateInventoryDailyReport()
{
    var userId = AuthHelper.GetCurrentUserId();
    var reportData = DapperRepository.QueryDataSet(
        "SELECT ProductName, ProductSKU, DailySales, DailyUsage FROM InventoryDailyMetrics WHERE CreatedBy = @uid",
        new { uid = userId }
    );
    DataTable rawMetrics = reportData.Tables[0];

    DataTable structuredTable = new DataTable("InventoryDaily");

    string[] staticCols = { "Product", "SKU", "Metric Type" };
    foreach (var colName in staticCols)
    {
        structuredTable.Columns.Add(colName, typeof(string));
    }

    for (int day = 1; day <= 31; day++)
    {
        structuredTable.Columns.Add($"{day}st", typeof(decimal?));
    }

    foreach (DataRow metricRow in rawMetrics.Rows)
    {
        var productLabel = metricRow["ProductName"].ToString();
        var skuIdentifier = metricRow["ProductSKU"].ToString();
        var dailySalesList = metricRow["DailySales"].ToString().Split(',', StringSplitOptions.None);
        var dailyUsageList = metricRow["DailyUsage"].ToString().Split(',', StringSplitOptions.None);

        var salesRow = structuredTable.NewRow();
        salesRow[0] = productLabel;
        salesRow[1] = skuIdentifier;
        salesRow[2] = "Units Sold";
        for (int d = 0; d < 31; d++)
        {
            if (decimal.TryParse(dailySalesList[d], out decimal salesVal))
            {
                salesRow[d + 3] = salesVal;
            }
        }
        structuredTable.Rows.Add(salesRow);

        var usageRow = structuredTable.NewRow();
        usageRow[0] = productLabel;
        usageRow[1] = skuIdentifier;
        usageRow[2] = "Units Consumed";
        for (int d = 0; d < 31; d++)
        {
            if (decimal.TryParse(dailyUsageList[d], out decimal usageVal))
            {
                usageRow[d + 3] = usageVal;
            }
        }
        structuredTable.Rows.Add(usageRow);
    }

    var fileName = NPOIExcelExporter.SaveAndFormatInventoryReport(structuredTable);
    return File(Path.Combine(AppSettings.ExportDirectory, fileName), "application/vnd.ms-excel", fileName);
}
private static ISheet ApplyInventoryReportStyling(ISheet worksheet, int totalDataRows)
{
    int rowIndex = 1;
    while (rowIndex <= totalDataRows - 1)
    {
        for (int colIndex = 0; colIndex < 3; colIndex++)
        {
            var mergeRange = new CellRangeAddress(rowIndex, rowIndex + 1, colIndex, colIndex);
            worksheet.AddMergedRegion(mergeRange);
        }
        rowIndex += 2;
    }

    int maxRow = worksheet.LastRowNum;
    int maxCol = 0;
    for (int i = 0; i <= maxRow; i++)
    {
        var currentRow = worksheet.GetRow(i);
        if (currentRow != null)
        {
            maxCol = Math.Max(maxCol, currentRow.LastCellNum - 1);
        }
    }

    IWorkbook parentWorkbook = worksheet.Workbook;
    ICellStyle centeredStyle = parentWorkbook.CreateCellStyle();
    centeredStyle.Alignment = HorizontalAlignment.Center;
    centeredStyle.VerticalAlignment = VerticalAlignment.Center;
    IFont headerFont = parentWorkbook.CreateFont();
    headerFont.Boldweight = (short)FontBoldWeight.Bold;
    ICellStyle headerStyle = parentWorkbook.CreateCellStyle();
    headerStyle.CloneStyleFrom(centeredStyle);
    headerStyle.SetFont(headerFont);

    for (int i = 0; i <= maxRow; i++)
    {
        IRow currentRow = worksheet.GetRow(i) ?? worksheet.CreateRow(i);
        currentRow.HeightInPoints = 18;
        for (int j = 0; j <= maxCol; j++)
        {
            ICell currentCell = currentRow.GetCell(j) ?? currentRow.CreateCell(j);
            currentCell.CellStyle = i == 0 ? headerStyle : centeredStyle;
            worksheet.SetColumnWidth(j, (j < 3 ? 22 : 10) * 256);
        }
    }

    return worksheet;
}
public static string SaveAndFormatInventoryReport(DataTable reportTable)
{
    IWorkbook excelWorkbook = new HSSFWorkbook();
    ISheet inventorySheet = excelWorkbook.CreateSheet("Daily Inventory Metrics");

    IRow headerRow = inventorySheet.CreateRow(0);
    for (int i = 0; i < reportTable.Columns.Count; i++)
    {
        ICell headerCell = headerRow.CreateCell(i);
        headerCell.SetCellValue(reportTable.Columns[i].ColumnName);
    }

    for (int dataIdx = 0; dataIdx < reportTable.Rows.Count; dataIdx++)
    {
        DataRow sourceRow = reportTable.Rows[dataIdx];
        IRow targetRow = inventorySheet.CreateRow(dataIdx + 1);

        for (int colIdx = 0; colIdx < reportTable.Columns.Count; colIdx++)
        {
            ICell targetCell = targetRow.CreateCell(colIdx);
            if (sourceRow[colIdx] is decimal decimalValue)
            {
                targetCell.SetCellValue(decimalValue);
            }
            else
            {
                targetCell.SetCellValue(sourceRow[colIdx]?.ToString() ?? string.Empty);
            }
        }
    }

    ApplyInventoryReportStyling(inventorySheet, reportTable.Rows.Count);

    string exportFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "GeneratedReports");
    if (!Directory.Exists(exportFolder))
    {
        Directory.CreateDirectory(exportFolder);
    }

    string outputFileName = $"InventoryReport_{DateTime.UtcNow:yyyyMMddHHmmssfff}.xls";
    string fullOutputPath = Path.Combine(exportFolder, outputFileName);

    using (var fileStream = new FileStream(fullOutputPath, FileMode.Create, FileAccess.Write))
    {
        excelWorkbook.Write(fileStream);
    }

    return outputFileName;
}

Tags: C# NPOI Excel Export Excel Formatting DataTable

Posted on Sat, 16 May 2026 23:12:04 +0000 by djcee