ASP.NETでExcelファイルを作成・ダウンロードさせる

こんにちは井上です。

ASP.NETでのEXCEL作成はネット上で検索すると結構ヒットするのですが、今回用いるパッケージについては情報量が比較的少なく、比較的頻度の高いプロパティ等に触れられていないケースが多かったので備忘録がてら纏ました。

パッケージはEPPlusです。

NuGet Gallery | EPPlus 5.8.6

OpenXMLを作成する他パッケージとしてClosedXML等もありますが、EPPlusを選んだ理由は安定版のなかでもよりDL数が多く更新頻度の高いパッケージであるためです。
尚、ClosedXMLは私の環境では少し長いコードを書いていると例外が発生して残念ながら使えませんでした。
Microsoft.Office.Interop.Excelを用いてExcel作成も可能ですが、こちらはおなじみのリソース解放が大変なのと(解放が漏れるとタスクマネージャーにExcelが続々現れる)、そもそもMSが推奨していないので採用できません。

Archived MSDN and TechNet Blogs | Microsoft Docs

EEPlusはOpenXMLを作成するだけですのでそこらへんは気にしなくても良いので楽チンです。

環境

.NET Framework 4.5.1
ASP.NET MVC
C#
EPPlus 4.0.4

Nugetでゲットする

f:id:ihisa:20151009132438p:plain

Excel作成処理

using OfficeOpenXml;
using System;
using System.IO;
using System.Web.Mvc;

~

[AcceptVerbs(HttpVerbs.Post)]
[ActionName("Index")]
public ActionResult Download()
{
    // excel
    using (var excel = new ExcelPackage())
    using (var worksheet = excel.Workbook.Worksheets.Add("ワークシート名"))
    {
        // フォント指定(列:1から5列、行1から10列なので、A1:E10を指す)
        worksheet.Cells[1, 1, 10, 5].Style.Font.Name = "MS Pゴシック";
        
        // フォントサイズ指定
        worksheet.Cells[1, 1, 10, 5].Style.Font.Size = 10;

        // 文字設定(A2セルを指す)
        worksheet.Cells[2, 1].Value = "今日の売上!";

        // セル結合(A2とB2,C2を結合)
        worksheet.Cells[2, 1, 2, 3].Merge = true;

        // センタリング
        worksheet.Cells[2, 1].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;

        // 太字
        worksheet.Cells[2, 1].Style.Font.Bold = true;
        
        // 文字色指定
        worksheet.Cells[2, 1].Style.Font.Color.SetColor(System.Drawing.Color.Red);
        
        // 罫線
        using (var list = worksheet.Cells[5, 1, 8, 4])
        {
            list.Style.Border.Top.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
            list.Style.Border.Right.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
            list.Style.Border.Bottom.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
            list.Style.Border.Left.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
        }
        
        using (var listheader = worksheet.Cells[5, 1, 5, 4])
        {
            // セル背景色
            listheader.Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
            listheader.Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.Blue);
            listheader.Style.Font.Color.SetColor(System.Drawing.Color.White);

            // 中央寄せ
            listheader.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
        }

        // 書式(Valueはobject型。数値をそのままセットすると書式も数値となる)
        worksheet.Cells[5, 1].Value = "商品";
        worksheet.Cells[5, 2].Value = "単価";
        worksheet.Cells[5, 3].Value = "売上数";
        worksheet.Cells[5, 4].Value = "合計";

        worksheet.Cells[6, 1].Value = "りんご";
        worksheet.Cells[6, 2].Value = 100;
        worksheet.Cells[6, 3].Value = 25;

        worksheet.Cells[7, 1].Value = "みかん";
        worksheet.Cells[7, 2].Value = 90;
        worksheet.Cells[7, 3].Value = 10;

        worksheet.Cells[8, 1].Value = "ばなな";
        worksheet.Cells[8, 2].Value = 120;
        worksheet.Cells[8, 3].Value = 20;

        worksheet.Cells[6, 2, 8, 3].Style.Numberformat.Format = "0.00";

        // 計算式
        worksheet.Cells[6, 4].Formula = "B6 * C6";
        worksheet.Cells[7, 4].Formula = "B7 * C7";
        worksheet.Cells[8, 4].Formula = "B8 * C8";

        // 印刷設定            
        worksheet.PrinterSettings.Orientation = eOrientation.Landscape;
        worksheet.PrinterSettings.FitToPage = true;
        worksheet.PrinterSettings.FitToWidth = 1;
        worksheet.PrinterSettings.FitToHeight = 0;
        
        // 幅調整
        worksheet.Cells.AutoFitColumns();
        worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns();
        worksheet.Cells[1, 1].AutoFitColumns(10);
        worksheet.Cells[1, 2].AutoFitColumns(20);
        worksheet.Cells[1, 3].AutoFitColumns(10);
        worksheet.Cells[1, 4].AutoFitColumns(10);

        // グラフ
        using (var chart = worksheet.Drawings.AddChart("グラフ", OfficeOpenXml.Drawing.Chart.eChartType.BarClustered))
        {
            chart.SetPosition(10, 0, 0, 0);
            chart.SetSize(400, 400);
            chart.Series.Add("D6:D8", "A6:A8");
        }

        // 画像設定
        using (var picture = worksheet.Drawings.AddPicture("画像", new FileInfo(Server.MapPath("~/Content/Images/sanwa.png"))))
        {
            picture.SetPosition(33, 0, 0, 0);
        }

        // ページヘッダ設定
        worksheet.HeaderFooter.OddHeader.LeftAlignedText = "Excel出力";

        // ページフッタ設定(ページ番号/総ページ数)
        worksheet.HeaderFooter.OddFooter.RightAlignedText = String.Format("{0} / {1}", ExcelHeaderFooter.PageNumber, ExcelHeaderFooter.NumberOfPages);

        // ページフッタ幅
        worksheet.PrinterSettings.FooterMargin = (decimal)(0.8 / 2.54);
        worksheet.PrinterSettings.BottomMargin = (decimal)(1.5 / 2.54);

        // ページサイズ
        worksheet.PrinterSettings.PaperSize = ePaperSize.A4;

        // 用紙内にサイズ調整
        worksheet.PrinterSettings.FitToHeight = 1;
        worksheet.PrinterSettings.FitToWidth = 1;

        // 出力
        using (MemoryStream ms = new MemoryStream())
        {
            excel.SaveAs(ms);
            return File(ms.ToArray(), "application/msexcel", "ダウンロードファイル名.xlsx");
        }
    }
}

出力ファイル

f:id:ihisa:20151027223717p:plain

あっという間にできました。
このパッケージのプロパティはExcel VBAプロパティ/メソッド名と近しい名前となっていますので、一度でもExcelをマクロでいじったことがあるような方でしたら直ぐにわかるかと思います。
同様にMicrosoft.Office.Interop.Excel名前空間内のプロパティ/メソッド名とも近いですね。
Excelはなんだかんだで重宝される形式ではありますので覚えておいて損はないかと思います。