前言
总是有很多朋友咨询Magicodes.IE如何基于ASP.NET Core导出Excel,出于从框架的体验和易用性的角度,Magicodes.IE决定对Excel的导出进行独立封装,以便于大家更易于使用,开箱即用
注意:Magicodes.IE是从框架的易用性和体验的角度对Excel导出进行了封装,但是希望大家先理解原理后再使用
1.安装包
2.引用命名空间
using Magicodes.ExporterAndImporter.Excel.AspNetCore;
3.直接使用XlsxFileResult
[ApiController] [Route("api/[controller]")] public class XlsxFileResultTests : ControllerBase { /// <summary> /// 使用Byte数组导出Excel文件 /// </summary> /// <returns></returns> [HttpGet("ByBytes")] public async Task<ActionResult> ByBytes() { //随机生成100条数据 var list = GenFu.GenFu.ListOf<ExportTestDataWithAttrs>(100); var exporter = new ExcelExporter(); var bytes = await exporter.ExportAsByteArray<ExportTestDataWithAttrs>(list); //使用XlsxFileResult进行导出 return new XlsxFileResult(bytes: bytes); } /// <summary> /// 使用流导出Excel文件 /// </summary> /// <returns></returns> [HttpGet("ByStream")] public async Task<ActionResult> ByStream() { //随机生成100条数据 var list = GenFu.GenFu.ListOf<ExportTestDataWithAttrs>(100); var exporter = new ExcelExporter(); var result = await exporter.ExportAsByteArray<ExportTestDataWithAttrs>(list); var fs = new MemoryStream(result); return new XlsxFileResult(stream: fs, fileDownloadName: "下载文件"); } /// <summary> /// 使用泛型集合导出Excel文件 /// </summary> /// <returns></returns> [HttpGet("ByList")] public async Task<ActionResult> ByList() { var list = GenFu.GenFu.ListOf<ExportTestDataWithAttrs>(100); return new XlsxFileResult<ExportTestDataWithAttrs>(data: list); } }
如上所示,引用 Magicodes.IE.Excel.AspNetCore
之后,导出就会变得如此简单。值得注意的是:
-
使用
XlsxFileResult
需引用包Magicodes.IE.Excel.AspNetCore
-
XlsxFileResult
继承自ActionResult
,目前支持字节数组、流和泛型集合为参数的Excel文件下载 -
支持传递下载文件名,参数名
fileDownloadName
,如不传则自动生成唯一的文件名
核心实现
Magicodes.IE.Excel.AspNetCore
中,我们添加了自定义的ActionResult
——XlsxFileResult
,核心参考代码如下所示:
/// <summary> /// Excel文件ActionResult /// </summary> /// <typeparam name="T"></typeparam> public class XlsxFileResult<T> : XlsxFileResultBase where T : class, new() { /// <summary> /// /// </summary> /// <param name="data"></param> /// <param name="fileDownloadName"></param> public XlsxFileResult(ICollection<T> data, string fileDownloadName = null) { FileDownloadName = fileDownloadName; Data = data; } public string FileDownloadName { get; } public ICollection<T> Data { get; } public async override Task ExecuteResultAsync(ActionContext context) { var exporter = new ExcelExporter(); var bytes = await exporter.ExportAsByteArray(Data); var fs = new MemoryStream(bytes); await DownloadExcelFileAsync(context, fs, FileDownloadName); } } /// <summary> /// /// </summary> public class XlsxFileResult : XlsxFileResultBase { /// <summary> /// /// </summary> /// <param name="stream"></param> /// <param name="fileDownloadName"></param> public XlsxFileResult(Stream stream, string fileDownloadName = null) { Stream = stream; FileDownloadName = fileDownloadName; } /// <summary> /// /// </summary> /// <param name="bytes"></param> /// <param name="fileDownloadName"></param> public XlsxFileResult(byte[] bytes, string fileDownloadName = null) { Stream = new MemoryStream(bytes); FileDownloadName = fileDownloadName; } public Stream Stream { get; protected set; } public string FileDownloadName { get; protected set; } public async override Task ExecuteResultAsync(ActionContext context) { await DownloadExcelFileAsync(context, Stream, FileDownloadName); } } /// <summary> /// 基类 /// </summary> public class XlsxFileResultBase : ActionResult { /// <summary> /// 下载Excel文件 /// </summary> /// <param name="context"></param> /// <param name="stream"></param> /// <param name="downloadFileName"></param> /// <returns></returns> protected virtual async Task DownloadExcelFileAsync(ActionContext context, Stream stream, string downloadFileName) { var response = context.HttpContext.Response; response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; if (downloadFileName == null) { downloadFileName = Guid.NewGuid().ToString("N") + ".xlsx"; } if (string.IsNullOrEmpty(Path.GetExtension(downloadFileName))) { downloadFileName += ".xlsx"; } context.HttpContext.Response.Headers.Add("Content-Disposition", new[] { "attachment; filename=" +HttpUtility.UrlEncode(downloadFileName) }); await stream.CopyToAsync(context.HttpContext.Response.Body); } }
最后
教程已上传Github,有兴趣有精力的朋友可以帮忙PR一下单元测试,由于精力有限,先手测了,可参考:
-
ASP.NET Core 中的测试控制器逻辑 | Microsoft Docs
写个功能几分钟到十几分钟,码个文档要半天,就此结束。
Magicodes.IE:导入导出通用库,支持Dto导入导出、模板导出、花式导出以及动态导出,支持Excel、Csv、Word、Pdf和Html。
-
Github:https://github.com/dotnetcore/Magicodes.IE
-
码云(手动同步,不维护):https://gitee.com/magicodes/Magicodes.IE
相关库会一直更新,在功能体验上有可能会和本文教程有细微的出入,请以相关具体代码、版本日志、单元测试示例为准。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构