[ClosedXML]ASP.Net MVC5 使用ThirdParty來匯出Excel

MVC 5 使用Ajax 和 ClosedXML 來匯出Excel

最近在寫一個練習,被指定要用ClosedXML

又在寫Code的過程中 踩了無限多個洞..所以才想說要把這篇文章給生出來..

先說明一下我匯出Excel曾經用過的方式

我想應該有很多種選擇,譬如直接using Microsoft.office.Interop.Excel或者是NPOI或者是EPPlus等等

而我本身在使用NPOI的時候 覺得套件的用法不是這麼直覺 封裝得太好了

在使用Interop.Excel時感覺跟NPOI差不多,所以在我摸過ClosedXML之前 其實是比較愛用EPPlus的

那為什麼ClosedXML好用呢? 因為寫Code的行數少了很多..(好吧 我真的很懶)

不過可能是不太熟 而且網路上大部分都是提供DataTable的範例

這次的範例是使用Linq的Query結果來將資料帶入到套件中..

結果沒想到卻搞了蠻多天的...Orz..

下面是前端發出Ajax的語法 這應該沒甚麼問題

但是成功的時候一定要用window.location.href來接,因為要這樣才會認為是要下載一個檔案

不然你會發現status是200 data是亂碼(其實是excel檔..但瀏覽器把它當文字的樣子),檔案卻沒有下載下來!!

<div>
  <button d="export">匯出</button>
</div>

<script type="text/javascript">
  $("#export").click(function () {
        $.ajax({
            url: "@Url.Action("cusDataExport")",
            success: function (response, textStatus, jqXHR) {
                window.location.href = '@Url.Action("cusDataExport", "客戶資料")';
            },
            error: function (xhr, status, error) {
                alert(error);
            }
        });
    });
</script>

再來就是Action的部分了..

public ActionResult cusDataExport()
{
    //ClosedXML的用法 先new一個Excel Workbook
    using (XLWorkbook wb = new XLWorkbook())
    {
        //取得我要塞入Excel內的資料
        var data = 客戶資料repo.All().Select(c => new { c.客戶名稱, c.電話, c.地址 });

        //一個wrokbook內至少會有一個worksheet,並將資料Insert至這個位於A1這個位置上
        var ws = wb.Worksheets.Add("cusdata", 1);
        //注意官方文件上說明,如果是要塞入Query後的資料該資料一定要變成是data.AsEnumerable()
        //但是我查詢出來的資料剛好是IQueryable ,其中IQueryable有繼承IEnumerable 所以不需要特別寫
        ws.Cell(1, 1).InsertData(data);
             
        //因為是用Query的方式,這個地方要用串流的方式來存檔
        using (MemoryStream memoryStream = new MemoryStream())
        {
            wb.SaveAs(memoryStream);
            //請注意 一定要加入這行,不然Excel會是空檔
            memoryStream.Seek(0, SeekOrigin.Begin);
            //注意Excel的ContentType,是要用這個"application/vnd.ms-excel" 不曉得為什麼網路上有的Excel ContentType超長,xlsx會錯 xls反而不會
            return this.File(memoryStream.ToArray(), "application/vnd.ms-excel", "Download.xlsx");
        }
    }
}

Code本來蠻簡潔有力的加了一堆註解後感覺變得很髒的感覺

那是因為真的太多細節要說了

1.千萬不要加上[HttpPost]這一個ActionFilter

因為在前端Ajax的確是用post的方式發出Request,但是不要忘了在成功的時候

可是用window.location.href來接 這時候就是用Get了

2.  在InsertData的時候ws.Cell(1, 1).InsertData(data) Query的結果一定是要AsEnumerable 

不然資料是不會複製到worksheet裡面的

3. 一定要加memoryStream.Seek(0, SeekOrigin.Begin)不然檔案會是空檔

4.ContentType很重要

不知道為什麼我在網路上查到xlsx的ContentType是application/vnd.openxmlformats-officedocument.spreadsheetml.sheet

但是實際上用application/vnd.ms-excel就可以了

5.ClosedXML只支援2007以上的Excel版本 但是如果在return File的時候Download.xlsx 改成xls 是可以的

因為ClosedXML產生出來xlsx只是在轉型成為xls罷了

匯出的Excel會長這樣

 

以上如有謬誤 還請不吝指教 感謝

參考文章

jQeury Ajax http://api.jquery.com/jquery.ajax/

ClosedXML Example https://github.com/closedxml/closedxml/wiki/Copying-IEnumerable-Collections

Ajax Download File Http Post & Get http://geekswithblogs.net/rgupta/archive/2014/06/23/downloading-file-using-ajax-and-jquery-after-submitting-form-data.aspx

-----------------------------------------

有時在會走之前你就得跑

你不解決問題 就等問題解決你