在專案中,若有查詢清單功能,免俗不了有匯出的功能,匯出檔案格式最方便就是csv格式,只要用逗點分隔,超簡單。
但現行大家常用的,依然還是Microsoft Office的Excel為大宗,因此我們可以透過一些免費的套件將資料匯出成Excel(.xlsx檔)。
今天實作透過EPPlus將資料轉成Excel並讓使用者可以下載。
首先,透過Nuget下載EPPlus套件,直接取用最新版即可。

接著實作
public ActionResult Export()
{
    //取出要匯出Excel的資料
    List<RANGER> rangerList = db.RANGER.ToList();
    //建立Excel
    ExcelPackage ep = new ExcelPackage();
    //建立第一個Sheet,後方為定義Sheet的名稱
    ExcelWorksheet sheet = ep.Workbook.Worksheets.Add("FirstSheet");
    int col = 1;    //欄:直的,因為要從第1欄開始,所以初始為1
    //第1列是標題列 
    //標題列部分,是取得DataAnnotations中的DisplayName,這樣比較一致,
    //這也可避免後期有修改欄位名稱需求,但匯出excel標題忘了改的問題發生。
    //取得做法可參考最後的參考連結。
    sheet.Cells[1, col++].Value = DisplayAttributeHelper<RANGER>.GetDisplayName("Name");
    sheet.Cells[1, col++].Value = DisplayAttributeHelper<RANGER>.GetDisplayName("Grade");
    sheet.Cells[1, col++].Value = DisplayAttributeHelper<RANGER>.GetDisplayName("Type");
    sheet.Cells[1, col++].Value = DisplayAttributeHelper<RANGER>.GetDisplayName("AttackDistance");
    sheet.Cells[1, col++].Value = DisplayAttributeHelper<RANGER>.GetDisplayName("AttackArea");
    sheet.Cells[1, col++].Value = DisplayAttributeHelper<RANGER>.GetDisplayName("MovingSpeed");
    sheet.Cells[1, col++].Value = DisplayAttributeHelper<RANGER>.GetDisplayName("AttackSpacing");
    sheet.Cells[1, col++].Value = DisplayAttributeHelper<RANGER>.GetDisplayName("AttackTime");
    sheet.Cells[1, col++].Value = DisplayAttributeHelper<RANGER>.GetDisplayName("NormalCD");
    sheet.Cells[1, col++].Value = DisplayAttributeHelper<RANGER>.GetDisplayName("MasterDPS");
    sheet.Cells[1, col++].Value = DisplayAttributeHelper<RANGER>.GetDisplayName("MasterDEF");
    sheet.Cells[1, col++].Value = DisplayAttributeHelper<RANGER>.GetDisplayName("MasterHP");
    sheet.Cells[1, col++].Value = DisplayAttributeHelper<RANGER>.GetDisplayName("Mine");
    
    //資料從第2列開始
    int row = 2;    //列:橫的
    foreach (RANGER item in rangerList)
    {
        col = 1;//每換一列,欄位要從1開始
                //指定Sheet的欄與列(欄名列號ex.A1,B20,在這邊都是用數字),將資料寫入
        sheet.Cells[row, col++].Value = item.Name;
        sheet.Cells[row, col++].Value = item.Grade;
        sheet.Cells[row, col++].Value = item.Type;
        sheet.Cells[row, col++].Value = item.AttackDistance;
        sheet.Cells[row, col++].Value = item.AttackArea;
        sheet.Cells[row, col++].Value = item.MovingSpeed;
        sheet.Cells[row, col++].Value = item.AttackSpacing;
        sheet.Cells[row, col++].Value = item.AttackTime;
        sheet.Cells[row, col++].Value = item.NormalCD;
        sheet.Cells[row, col++].Value = item.MasterDPS;
        sheet.Cells[row, col++].Value = item.MasterDEF;
        sheet.Cells[row, col++].Value = item.MasterHP;
        sheet.Cells[row, col++].Value = item.Mine;
        row++;
    }
    //因為ep.Stream是加密過的串流,故要透過SaveAs將資料寫到MemoryStream,在將MemoryStream使用FileStreamResult回傳到前端
    MemoryStream fileStream = new MemoryStream();
    ep.SaveAs(fileStream);
    ep.Dispose();//如果這邊不下Dispose,建議此ep要用using包起來,但是要記得先將資料寫進MemoryStream在Dispose。
    fileStream.Position = 0;//不重新將位置設為0,excel開啟後會出現錯誤
    return File(fileStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "ExportRanger.xlsx");
}
遇到問題:excel開啟後,可能會出現下圖的錯誤

可以先檢查下列項目
- 副檔名是否有誤
 -  回傳的MIME Content-type是否正確
可以參考這篇找對應的Content-type:Microsoft Office MIME Types -  將ep.Stream寫入MemoryStream後,MemoryStream要先把position先指到0,再return。

 
最後展現一下成果

(資料來源為Line Ranger,僅限測試資料之用途)
總結:
這次實作只是簡單的將資料塞入,並沒有使用很多華麗的技術,例如給予欄位顏色、欄位置中、自動欄寬....等等,當然EPPlus都是可以做得到的,有興趣的朋友可以到官方網站下載SampleCode。
此套件並沒有正式的文件,以下引用官網之說明。
EPPlus Documentation
The best way to learn how to use this library is to download the sample project and step through the samples.
除了EPPlus,也有其他的套件,如NPOI,網路上也有蠻多人比較評比,就看各位客倌選擇了。
參考資料
- 比NPOI更討喜的Excel元件-EPPlus!
 - Generating an excel file with EPPlus is failing
 - 取得 Entity 類別 MetaData 所設定的 Display Name
 

本著作由Chenting Weng製作,以創用CC 姓名標示 4.0 國際 授權條款釋出。
This work by Chenting Weng is licensed under a Creative Commons Attribution 4.0 International License.
Based on a work at https://dotblogs.com.tw/chentingw.
部分文章內容會引用到其他網站的簡介或圖片,若有侵犯到您的著作權,請留言告知,本人會儘快移除。
免責聲明:文章屬個人記事使用,僅供參考,若引用文章造成一切損失,本人不承擔任何責任。如有錯誤,歡迎留言告知。
Part of the content of the article will refer to the profile or picture of other websites.
If there is any infringement of your copyright, please leave a message and let me remove it as soon as possible.
Disclaimer:The article is for personal use and is for reference only. I will not bear any responsibility for any loss caused by quoting the article. If there is an error, please leave a message to inform.

