Shoeisha Technology Media

CodeZine(コードジン)

特集ページ一覧

サーバーサイドでExcelファイルを読み書きするWebアプリケーションを作る

ASP.NET MVCやMicrosoft Azure Functions上でExcel処理を記述しよう

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加
2017/05/26 14:00
目次

機能(1) Excelファイルから値を読み取りデータを登録する

 それでは、Excelコンポーネントを使用した機能を実装します。はじめに、以下の図のようなExcel2016のファイルをWebアプリケーションにアップロードすると、記載した内容のデータを一括で登録する機能を実装します。

一行につき1つのデータの内容を記述したExcelファイル)
一行につき1つのデータの内容を記述したExcelファイル)

手順

 Webアプリケーションにファイルをアップロードするためのフォームを作成します。「Models」フォルダに「UploadModel.cs」クラスを、「Views」の下の「TrainingLogs」フォルダ(※)に「Upload.cshtml」を作成し、次のように記述します。これらの記述はASP.NET MVCにてファイルをアップロードする機能の一般的な実装になりますので、説明を省きます。

※ 「Views」の下の「TrainingLogs」フォルダは、前述の「スキャフォールディング」の手順により生成されたフォルダです。

UploadModel.cs
using System.Web;

namespace Miso.C1ExcelSample.Models
{
	public class UploadModel
	{
		public HttpPostedFileWrapper PostedFile { get; set; }
	}
}
Upload.cshtml
@{ 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にアップデートできます。

「/TrainingLogs/Upload」にアクセスしたときの画面
「/TrainingLogs/Upload」にアクセスしたときの画面

 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」といったように、行インデックスと列のインデックスを指定して、テキストの値を読み取ります。


  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • 矢後 比呂加(ヤゴ ヒロカ)

     Microsoft MVP for Visual Studio and Development Technologies(https://mvp.microsoft.com/ja-jp/PublicProfile/5000246)  シグマコンサルティング株式会社にて、Microsoft Azu...

バックナンバー

連載:ComponentZine(ComponentOne Studio)

もっと読む

All contents copyright © 2005-2019 Shoeisha Co., Ltd. All rights reserved. ver.1.5