機能(1) Excelファイルから値を読み取りデータを登録する
それでは、Excelコンポーネントを使用した機能を実装します。はじめに、以下の図のようなExcel2016のファイルをWebアプリケーションにアップロードすると、記載した内容のデータを一括で登録する機能を実装します。
手順
Webアプリケーションにファイルをアップロードするためのフォームを作成します。「Models」フォルダに「UploadModel.cs」クラスを、「Views」の下の「TrainingLogs」フォルダ(※)に「Upload.cshtml」を作成し、次のように記述します。これらの記述はASP.NET MVCにてファイルをアップロードする機能の一般的な実装になりますので、説明を省きます。
※ 「Views」の下の「TrainingLogs」フォルダは、前述の「スキャフォールディング」の手順により生成されたフォルダです。
using System.Web; namespace Miso.C1ExcelSample.Models { public class UploadModel { public HttpPostedFileWrapper PostedFile { get; set; } } }
@{ ViewBag.Title = "Upload"; } @model Miso.C1ExcelSample.Models.UploadModel <h2>Upload</h2> <form action="/TrainingLogs/Upload" enctype="multipart/form-data" method="post"> @Html.AntiForgeryToken() @Html.ValidationSummary(excludePropertyErrors: false, message: "", htmlAttributes: new { @class = "text-danger" }) <input type="file" name="@Html.NameFor(m => m.PostedFile)" /> <input type="submit" value="Upload"/> </form> <div> @Html.ActionLink("Back to List", "Index") </div>
次に、「TrainingLogsController.cs」のクラスの中に、次のようにメソッドを2つ追記します。
[HttpGet] public ActionResult Upload() { return View(); } [HttpPost] [ValidateAntiForgeryToken] public async Task<ActionResult> Upload(UploadModel model) { //ファイルが送信されているか検証します if ((model?.PostedFile?.ContentLength ?? 0) == 0) { ModelState.AddModelError(nameof(model.PostedFile), "ファイルを送信して下さい。"); return View(); } Stream stream = model.PostedFile.InputStream; //C1XLBookオブジェクトを作成し、送信されたExcelファイルを読み込みます。 var excelBook = new C1XLBook(); excelBook.Load(stream, FileFormat.OpenXml); var logList = new List<TrainingLog>(); //Excelに入力のある行数を取得します int inputMaxRowCount = excelBook.Sheets[0].Rows.Count; for(int rowIndex = 0; rowIndex < (inputMaxRowCount - 1); rowIndex += 1) { if (rowIndex == 0) continue; //最初の行はヘッダー行なので処理しない //日付のセルの値を取得します var dateValue = excelBook.Sheets[0].GetCell(rowIndex, colIndex:0)?.Text; if (!DateTime.TryParse(dateValue, out DateTime date)) { //日付でない場合は処理をしない continue; } string name = excelBook.Sheets[0].GetCell(rowIndex, 1)?.Value as string; double.TryParse(excelBook.Sheets[0].GetCell(rowIndex, 2)?.Text, out double bodyWeight); int.TryParse(excelBook.Sheets[0].GetCell(rowIndex, 3)?.Text, out int squatCount); int.TryParse(excelBook.Sheets[0].GetCell(rowIndex, 4)?.Text, out int pushupCount); int.TryParse(excelBook.Sheets[0].GetCell(rowIndex, 5)?.Text, out int situpCount); var log = new TrainingLog { Date = date, Name = name, BodyWeight = bodyWeight, SquatCount = squatCount, PushupCount = pushupCount, SitupCount = situpCount, }; logList.Add(log); } //データを保存します db.TrainingLogs.AddRange(logList); await db.SaveChangesAsync(); return RedirectToAction("Index"); }
実行例
ここで、Webアプリケーションをデバッグ実行し、URL「/TrainingLogs/Upload」にアクセスして先ほどのExcelファイルをアップロードします。
補足
ここでC# 7の文法に関するコンパイルエラーが発生する場合は、NuGetパッケージ「Microsoft.Net.Compilers」をバージョンアップしてください。執筆時はバージョン2.1にアップデートできます。
Excelファイルをアップロードした後、「TrainingLogs/」でアクセスする一覧画面にて、複数のデータが登録できたことを確認します。
解説
これで機能(1)の実装は完了です。「TrainingLogsController.cs」に追記したUploadメソッドについて補足します。ファイルを送信された時に実行するUploadメソッドが、Excelファイルを読み取り、データを登録する処理を行っている部分です。
このUploadメソッドではまず、C1XLBookオブジェクト(C1.C1Excel名前空間)を生成し、C1XLBook クラスのLoadメソッドにて、送信されたExcelのファイルの内容をロードしています。このLoadメソッドでは、Streamオブジェクト(System.IO名前空間)やファイルパスの指定によりExcelファイルを読み取ることができます。第二引数では、Excelファイルのバージョンを指定しています。
Stream stream = model.PostedFile.InputStream; //C1XLBookオブジェクトを作成し、送信されたExcelファイルを読み込みます。 var excelBook = new C1XLBook(); excelBook.Load(stream, FileFormat.OpenXml);
次に、Excelファイルに入力されている行数の最大値を「excelBook.Sheets[0].Rows.Count」で取得し、入力された行数分ループし、その行に記述されたセルの値を読み取ります。
//Excelに入力のある行数を取得します int inputMaxRowCount = excelBook.Sheets[0].Rows.Count; for(int rowIndex = 0; rowIndex < (inputMaxRowCount - 1); rowIndex += 1) { if (rowIndex == 0) continue; //最初の行はヘッダー行なので処理しない //日付のセルの値を取得します var dateValue = excelBook.Sheets[0].GetCell(rowIndex, colIndex:0)?.Text; //省略
セルの値は、「excelBook.Sheets[0].GetCell(rowIndex, colIndex:0)?.Text」といったように、行インデックスと列のインデックスを指定して、テキストの値を読み取ります。