别用Excel原生COM组件导出,尤其服务器环境;推荐EPPlus或ClosedXML——它们不依赖Office安装、线程安全、可控性强。

直接说结论:别用“Excel”原生 COM 组件导出,尤其在服务器环境;推荐 EPPlus(.NET 5+ 用 EPPlus.Core 已停更,改用官方 EPPlus 6.x+)或 ClosedXML —— 它们不依赖 Excel 安装、线程安全、可控性强。
为什么 Microsoft.Office.Interop.Excel 在 Web 或后台服务里会崩
这个 COM 组件本质是启动本地 Excel 进程,Windows Server 默认没桌面交互会话,Excel.Application 初始化直接抛 COMException(错误码 0x80070005 或 0x80080005);即使强行配置 DCOM,也会因多线程争抢进程句柄导致卡死、内存泄漏、生成空文件。
- Web API / Windows Service / Azure Function 中绝对禁用
Interop - 开发机上能跑 ≠ 上线能跑,测试环境必须和生产一致(无 Office)
- 导出大表(>10 万行)时 Interop 内存占用飙升,GC 很难及时回收
EPPlus 导出 DataTable 到 Excel 的最小可行代码
它基于 Open XML,纯托管,支持 .NET Core 3.1+ 和 .NET 5+。注意:6.0+ 版本需手动接受许可证(免费用于非商业用途,商业需授权)。
var package = new ExcelPackage();
var worksheet = package.Workbook.Worksheets.Add("Data");
worksheet.Cells["A1"].LoadFromDataTable(dataTable, true); // true 表示首行为列名
// 可选:自动列宽
worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns();
// 输出流(供 ASP.NET Core File() 返回)
return File(package.Stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "export.xlsx");
-
LoadFromDataTable默认不处理 null 值,列类型为object时可能写成字符串 "NULL",建议提前用DataRow.IsNull()清洗 - 若字段含换行符
\n,需设置worksheet.Cells.Style.WrapText = true - 时间字段默认导出为 Excel 序列号(如 45123),要显示为日期需设格式:
worksheet.Column(3).Style.Numberformat.Format = "yyyy-mm-dd hh:mm:ss"
导出大数据量(50 万+ 行)时的性能关键点
EPPlus 全部数据进内存,单次导出超 100 万行易触发 OutOfMemoryException;ClosedXML 同样有此限制。真正可靠的方案是分块 + 流式写入。
- 避免一次性
LoadFromDataTable,改用循环worksheet.Cells[row, col].Value = value,但需控制每批 ≤ 5 万行并手动调用GC.Collect()(仅应急) - 更优解:用
SqlDataReader边读边写,配合worksheet.InsertRow()+row.Cells[col].Value,减少 DataTable 构建开销 - 导出前关闭样式自动计算:
package.Workbook.CalculateMode = OfficeOpenXml.ExcelCalculationMode.Manual - 若允许 CSV 替代 Excel,
StreamWriter直出速度提升 10 倍以上,且无内存压力
真正卡住人的从来不是“怎么写第一行代码”,而是导出后用户发现日期变数字、中文乱码、合并单元格错位、或者凌晨三点服务器报警内存爆了——这些细节都在初始化选项和数据预处理里,而不是文档末尾的“高级技巧”章节。


















