ASP.NET Web アプリケーションで Excelファイルをエクスポートするコードを紹介します。
概要
Webアプリケーションで結果などをExcelファイルでエクスポートする機能を実装したいことがあります。
この記事では、Open XML SDKを利用したExcelファイルのエクスポートの実装方法とコードを紹介します。
方針
Excelファイルを編集する場合、"Microsoft Excel Object Library" の
Microsoft.Office.Interop.Excel
アセンブリを参照して、
COMオブジェクトを利用してExcelファイルを編集する方法があります。(実装方法は
こちらの記事を参照)
しかし、この方法はサーバーで利用するのは推奨されていないこと、COMオブジェクトのメモリ開放が複雑でメモリリークの原因になりやすいことからWebアプリケーションで利用するのは不適切です。
別の方法として、Open XML SDKを利用してExcelファイルの操作をする方法があります。この方法を利用するとWebアプリケーションでExcelファイルを出力することが比較的容易にできます。
事前準備
Open XML SDKをダウンロードしてプロジェクトにインストールします。詳しい手順は
こちらの記事を参照してください。
プログラム
今回はASP.NET Coreアプリケーションで作成します。ASP.NET WebForm アプリケーションで実装する場合は、ジェネリックハンドラー(*.ashx)を利用して同様に実装できます。
コード
下記のコードを記述します。(記載のないASP.NET Coreアプリケーションのほかのファイルは編集していません。)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace ExcelFileExport
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/excel", async context =>
{
ExcelExport ee = new ExcelExport();
await ee.Export(context);
});
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using System.IO;
namespace ExcelFileExport
{
public class ExcelExport
{
List<DataItem> dataList = new List<DataItem>();
class DataItem
{
public int id;
public string name;
public string code;
public int price;
}
public async Task Export(HttpContext context)
{
dataList.Clear();
dataList.Add(new DataItem() { id = 1, name = "ぺんぎんクッキー", code = "PCD-001", price = 180 });
dataList.Add(new DataItem() { id = 2, name = "あひるサブレ", code = "PCD-002", price = 120 });
dataList.Add(new DataItem() { id = 3, name = "らくだキャラメル", code = "PCD-003", price = 40 });
dataList.Add(new DataItem() { id = 4, name = "しろくまアイス", code = "PCA-001", price = 230 });
dataList.Add(new DataItem() { id = 5, name = "だちょうカステラ", code = "PCD-004", price = 90 });
//シート作成
MemoryStream ms = new MemoryStream();
SpreadsheetDocument doc = SpreadsheetDocument.Create(ms, SpreadsheetDocumentType.Workbook);
WorkbookPart wbpart = doc.AddWorkbookPart();
wbpart.Workbook = new Workbook();
WorksheetPart wspart = wbpart.AddNewPart<WorksheetPart>();
wspart.Worksheet = new Worksheet(new SheetData());
Sheets sheets = doc.WorkbookPart.Workbook.AppendChild<Sheets>(new Sheets());
Sheet sheet = new Sheet();
sheet.Id = doc.WorkbookPart.GetIdOfPart(wspart);
sheet.SheetId = 1;
sheet.Name = "商品";
sheets.Append(sheet);
//Column
Columns lstColumns = wspart.Worksheet.GetFirstChild<Columns>();
if (lstColumns == null) {
lstColumns = new Columns();
wspart.Worksheet.InsertAt(lstColumns, 0);
}
lstColumns.Append(new Column() { Min = 1, Max = 1, Width = 4, CustomWidth = true });
lstColumns.Append(new Column() { Min = 2, Max = 2, Width = 25, CustomWidth = true });
lstColumns.Append(new Column() { Min = 3, Max = 4, Width = 12, CustomWidth = true });
//データ挿入
Row row;
UInt32Value row_index = 1;
foreach (DataItem di in dataList) {
row = new Row() { RowIndex = row_index };
wspart.Worksheet.GetFirstChild<SheetData>().Append(row);
Cell refCell = null;
Cell newCell;
newCell = new Cell() { CellReference = "A" + row_index.ToString() };
newCell.CellValue = new CellValue(di.id.ToString());
newCell.DataType = new EnumValue<CellValues>(CellValues.Number);
row.InsertAfter(newCell, refCell);
refCell = newCell;
//
newCell = new Cell() { CellReference = "B" + row_index.ToString() };
newCell.CellValue = new CellValue(di.name);
newCell.DataType = new EnumValue<CellValues>(CellValues.String);
row.InsertAfter(newCell, refCell);
refCell = newCell;
//
newCell = new Cell() { CellReference = "C" + row_index.ToString() };
newCell.CellValue = new CellValue(di.code);
newCell.DataType = new EnumValue<CellValues>(CellValues.String);
row.InsertAfter(newCell, refCell);
refCell = newCell;
//
newCell = new Cell() { CellReference = "D" + row_index.ToString() };
newCell.CellValue = new CellValue(di.price.ToString());
newCell.DataType = new EnumValue<CellValues>(CellValues.Number);
row.InsertAfter(newCell, refCell);
refCell = newCell;
row_index++;
}
wbpart.Workbook.Save();
doc.Close();
ms.Seek(0, SeekOrigin.Begin);
byte[] buffer = new byte[ms.Length];
await ms.ReadAsync(buffer,0,(int)ms.Length);
ms.Close();
context.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
context.Response.Headers.Append("Content-Disposition", "attachment; filename=\"export.xlsx\"");
await context.Response.Body.WriteAsync(buffer, 0, buffer.Length);
}
}
}
解説
Startup.cs
endpoints.MapGet()
メソッドを実装します。
アプリケーションルートURL/excel
のURLにアクセスした場合に、Excelのファイルのダウンロードを開始します。
ダウンロードの処理は ExcelExport クラスに実装します。
endpoints.MapGet("/excel", async context =>
{
ExcelExport ee = new ExcelExport();
await ee.Export(context);
});
ExcelExport.cs
Excelファイルの作成とダウンロードを実行します。Opne XML SDK ファイルを利用したExcelファイルの生成については
こちらの記事を参照してください。今回の例では列幅も変更しています。列幅の変更は
こちらの記事を参照してください。
下記のデータ作成部分は実際のアプリケーションでは計算結果やデータベースから取得した結果を設定します。今回はダミーデータを挿入しています。
dataList.Add(new DataItem() { id = 1, name = "ぺんぎんクッキー", code = "PCD-001", price = 180 });
dataList.Add(new DataItem() { id = 2, name = "あひるサブレ", code = "PCD-002", price = 120 });
dataList.Add(new DataItem() { id = 3, name = "らくだキャラメル", code = "PCD-003", price = 40 });
dataList.Add(new DataItem() { id = 4, name = "しろくまアイス", code = "PCA-001", price = 230 });
dataList.Add(new DataItem() { id = 5, name = "だちょうカステラ", code = "PCD-004", price = 90 });
Excelのスプレッドシートのドキュメントは一般的にはファイルに作成しますが、今回はファイルをダウンロードしますのでMemoryStreamに保存します。
MemoryStream ms = new MemoryStream();
SpreadsheetDocument doc = SpreadsheetDocument.Create(ms, SpreadsheetDocumentType.Workbook);
ワークブックの保存後スプレッドシートを閉じます。
メモリストリームのシーク位置を先頭に移動し、byte配列のバッファにデータを読み出します。
wbpart.Workbook.Save();
doc.Close();
ms.Seek(0, SeekOrigin.Begin);
byte[] buffer = new byte[ms.Length];
await ms.ReadAsync(buffer,0,(int)ms.Length);
ms.Close();
byte配列のバッファの内容をレスポンスデーターとして書き込みます。書き込みには
Response.Body.WriteAsync()
メソッドを利用します。
Open XML のドキュメントのため、ContentTypeは
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
を指定しています。
また、今回はファイルをダウンロードしますので、Content-Disposition の値は
attachment
に設定し、
filename
フィールドを指定しています。ファイル名は export.xls としています。
context.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
context.Response.Headers.Append("Content-Disposition", "attachment; filename=\"export.xlsx\"");
await context.Response.Body.WriteAsync(buffer, 0, buffer.Length);
実行結果
プロジェクトを実行します。Webブラウザが起動しアプリケーションルートのページが表示されます。"Hello World!" のテキストが表示されます。
(アプリケーションルートURL)/excel
URLを開きます。
URLにアクセスすると、ファイルのダウンロードが始まります。ファイル名が "export.xlsx" となっていることが確認できます。
ダウンロードしたExcelのファイルを開きます。値が入力されているExcelファイルがダウンロードできていることが確認できます。
ASP.NET アプリケーションでExcelファイルをエクスポートする処理が実装できました。
参考 : ASP.NET WebFormアプリケーションでの実装例 (ジェネリックハンドラーを利用)
ASP.NET WebFormアプリケーションでの実装例です。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace ExcelFileExportWebForm
{
/// <summary>
/// Handler1 の概要の説明です
/// </summary>
public class Handler1 : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
ExcelExport ee = new ExcelExport();
ee.Export(context);
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using System.IO;
namespace ExcelFileExportWebForm
{
public class ExcelExport
{
List<DataItem> dataList = new List<DataItem>();
class DataItem
{
public int id;
public string name;
public string code;
public int price;
}
public void Export(HttpContext context)
{
dataList.Clear();
dataList.Add(new DataItem() { id = 1, name = "ぺんぎんクッキー", code = "PCD-001", price = 180 });
dataList.Add(new DataItem() { id = 2, name = "あひるサブレ", code = "PCD-002", price = 120 });
dataList.Add(new DataItem() { id = 3, name = "らくだキャラメル", code = "PCD-003", price = 40 });
dataList.Add(new DataItem() { id = 4, name = "しろくまアイス", code = "PCA-001", price = 230 });
dataList.Add(new DataItem() { id = 5, name = "だちょうカステラ", code = "PCD-004", price = 90 });
//シート作成
MemoryStream ms = new MemoryStream();
SpreadsheetDocument doc = SpreadsheetDocument.Create(ms, SpreadsheetDocumentType.Workbook);
WorkbookPart wbpart = doc.AddWorkbookPart();
wbpart.Workbook = new Workbook();
WorksheetPart wspart = wbpart.AddNewPart<WorksheetPart>();
wspart.Worksheet = new Worksheet(new SheetData());
Sheets sheets = doc.WorkbookPart.Workbook.AppendChild<Sheets>(new Sheets());
Sheet sheet = new Sheet();
sheet.Id = doc.WorkbookPart.GetIdOfPart(wspart);
sheet.SheetId = 1;
sheet.Name = "商品";
sheets.Append(sheet);
//Column
Columns lstColumns = wspart.Worksheet.GetFirstChild<Columns>();
if (lstColumns == null) {
lstColumns = new Columns();
wspart.Worksheet.InsertAt(lstColumns, 0);
}
lstColumns.Append(new Column() { Min = 1, Max = 1, Width = 4, CustomWidth = true });
lstColumns.Append(new Column() { Min = 2, Max = 2, Width = 25, CustomWidth = true });
lstColumns.Append(new Column() { Min = 3, Max = 4, Width = 12, CustomWidth = true });
//データ挿入
Row row;
UInt32Value row_index = 1;
foreach (DataItem di in dataList) {
row = new Row() { RowIndex = row_index };
wspart.Worksheet.GetFirstChild<SheetData>().Append(row);
Cell refCell = null;
Cell newCell;
newCell = new Cell() { CellReference = "A" + row_index.ToString() };
newCell.CellValue = new CellValue(di.id.ToString());
newCell.DataType = new EnumValue<CellValues>(CellValues.Number);
row.InsertAfter(newCell, refCell);
refCell = newCell;
//
newCell = new Cell() { CellReference = "B" + row_index.ToString() };
newCell.CellValue = new CellValue(di.name);
newCell.DataType = new EnumValue<CellValues>(CellValues.String);
row.InsertAfter(newCell, refCell);
refCell = newCell;
//
newCell = new Cell() { CellReference = "C" + row_index.ToString() };
newCell.CellValue = new CellValue(di.code);
newCell.DataType = new EnumValue<CellValues>(CellValues.String);
row.InsertAfter(newCell, refCell);
refCell = newCell;
//
newCell = new Cell() { CellReference = "D" + row_index.ToString() };
newCell.CellValue = new CellValue(di.price.ToString());
newCell.DataType = new EnumValue<CellValues>(CellValues.Number);
row.InsertAfter(newCell, refCell);
refCell = newCell;
//row.InsertBefore(
row_index++;
}
wbpart.Workbook.Save();
doc.Close();
ms.Seek(0, SeekOrigin.Begin);
byte[] buffer = new byte[ms.Length];
ms.ReadAsync(buffer, 0, (int)ms.Length);
ms.Close();
context.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
context.Response.Headers.Add("Content-Disposition", "attachment; filename=\"export.xlsx\"");
context.Response.BinaryWrite(buffer);
}
}
}
著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
最終更新日: 2021-05-16
作成日: 2020-10-18