ASP.NET CoreにおけるNPOIとNpoi.MapperによるExcelデータ高速変換実装

Excelファイルの読み書きは業務アプリケーション開発で頻繁に要求される機能です。従来のNPOIライブラリは高機能ですが、列のマッピングやフォーマット制御を手動で実装するとコードが冗長になりがちです。これを解決するために、データモデルとワークシートの列を自動的に対応付けることができるNpoi.Mapperを組み合わせる手法を解説します。このアプローチにより、数十行に及ぶ処理を最小限の記述で実現できます。

まず、プロジェクトに必要なパッケージをNuGet経由で追加します。

dotnet add package NPOI
dotnet add package Npoi.Mapper

データ変換の核心となるユーティリティクラスを作成します。ストリームを介してコレクションとExcelファイルを双方向に変換する静的メソッドを実装します。

using Npoi.Mapper;
using System.Collections.Generic;
using System.IO;
using System.Linq;

public static class WorkbookUtility
{
    public static MemoryStream SerializeCollectionToStream<T>(IEnumerable<T> dataItems, string worksheetTitle = "Data", bool replaceExisting = true, bool useOpenXmlFormat = true) where T : class
    {
        var serializer = new Mapper();
        var outputStream = new MemoryStream();
        serializer.Save<T>(outputStream, dataItems, worksheetTitle, replaceExisting, useOpenXmlFormat);
        return outputStream;
    }

    public static List<T> DeserializeStreamToCollection<T>(Stream inputStream, string targetSheet = null) where T : class
    {
        var reader = new Mapper(inputStream);
        var parsedRows = !string.IsNullOrWhiteSpace(targetSheet)
            ? reader.Take<T>(targetSheet)
            : reader.Take<T>();

        return parsedRows.Select(row => row.Value).ToList();
    }
}

次に、Excelの列と対応するエンティティを定義します。[Column]属性により、出力時の見出し名と列位置を明示的に制御できます。

using Npoi.Mapper;

public class Employee
{
    [Column("社員番号")]
    public int EmployeeId { get; set; }

    [Column("氏名")]
    public string DisplayName { get; set; }

    [Column("連絡先")]
    public string ContactNumber { get; set; }

    [Column("メールアドレス")]
    public string EmailAddress { get; set; }
}

コントローラーでは、ファイルアップロードからの読み込みと、動的なデータ生成からの書き出しを処理します。

using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;

public class DocumentController : Controller
{
    public IActionResult Index() => View();

    [HttpPost]
    public IActionResult ImportData()
    {
        var uploadedFile = Request.Form.Files[0];
        List<Employee> importedRecords = new List<Employee>();

        using var readStream = uploadedFile.OpenReadStream();
        importedRecords = WorkbookUtility.DeserializeStreamToCollection<Employee>(readStream, "Sheet1");

        return Ok(JsonConvert.SerializeObject(importedRecords));
    }

    public IActionResult ExportTemplate()
    {
        var sampleEntities = new List<Employee>();
        for (var i = 1; i <= 10; i++)
        {
            sampleEntities.Add(new Employee
            {
                EmployeeId = i,
                DisplayName = $"担当者{i:D2}",
                ContactNumber = "090-1234-5678",
                EmailAddress = $"staff{i}@example.jp"
            });
        }

        var resultStream = WorkbookUtility.SerializeCollectionToStream(sampleEntities);
        return File(resultStream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "employee_data.xlsx");
    }
}

ビュー側は簡易的なフォームとダウンロードリンクで構成します。

<@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers>

<a asp-action="ExportTemplate" class="btn btn-primary">データエクスポート</a>
<form asp-action="ImportData" method="post" enctype="multipart/form-data">
    <input type="file" name="files" accept=".xlsx,.xls" />
    <button type="submit">インポート実行</button>
</form>

実装完了後、エクスポート機能を実行すると、定義した属性に基づいて列見出しが正確に配置されたワークブックが生成されます。逆にインポート機能では、アップロードされたファイルの各行がEmployeeオブジェクトの配列にシームレスに変換され、JSON形式で返却されます。Npoi.Mapperが内部で行っているリフレクションと列インデックスの自動解決により、型安全かつ生産性の高いデータ処理パイプラインを構築できます。

タグ: ASP.NET Core NPOI Npoi.Mapper Excel C#

6月25日 16:40 投稿