Blazor WASM客户端导入显示Excel(.xlsx)文件(无需上传服务端)及慢加载修复
问题原因
Blazor WASM默认采用解释执行模式,而ClosedXML、NPOI这类重型Office操作库依赖大量反射、内存遍历操作,在解释模式下性能仅为Server端JIT执行的1/10~1/20,所以会出现数千行就卡顿的问题。
解决方案(按优先级排序)
1. 启用WASM AOT编译(性能提升最显著)
这是成本最低收益最高的优化方案,开启后WASM运行性能可达到原生.NET的60%~80%,实测1万行Excel加载速度可从20秒降低到3秒以内。
修改你的Blazor WASM项目.csproj文件,添加以下配置:
<PropertyGroup> <!-- 启用AOT编译 --> <RunAOTCompilation>true</RunAOTCompilation> <!-- .NET 7及以上版本可开启SIMD指令优化 --> <WasmEnableSIMD>true</WasmEnableSIMD> <!-- 启用裁剪优化,减少包体积 --> <PublishTrimmed>true</PublishTrimmed> </PropertyGroup>
同时将ClosedXML升级到最新的0.100+版本,该版本已针对WASM做了专门适配,移除了大量不必要的反射操作和System.Drawing依赖。
2. 优化现有读取代码
你现有代码存在两处冗余可优化,能进一步提升30%左右的加载速度:
- 移除多余的MemoryStream拷贝,直接使用IBrowserFile的读取流
- 关闭ClosedXML非必要的加载项,只读取必要的工作表内容
优化后的工具方法代码:
public static async Task<DataTable> GetDataTableFromExcel(IBrowserFile file) { DataTable dtTable = new DataTable(); // 放宽文件大小限制,根据业务调整,这里设置为最大100MB using var stream = file.OpenReadStream(maxAllowedSize: 100 * 1024 * 1024); // 关闭所有非必要加载项,进一步提升速度 var loadOptions = new XLLoadOptions { EventTracking = XLEventTracking.Disabled, LoadDocumentProperties = false, CalculateFormulas = false }; using var workBook = new XLWorkbook(stream, loadOptions); IXLWorksheet workSheet = workBook.Worksheet(1); bool firstRow = true; // 只读取已使用的行,跳过空行 foreach (IXLRow row in workSheet.RowsUsed()) { if (firstRow) { foreach (IXLCell cell in row.CellsUsed()) { dtTable.Columns.Add(cell.Value.ToString()); } firstRow = false; } else { dtTable.Rows.Add(); int i = 0; foreach (IXLCell cell in row.CellsUsed()) { dtTable.Rows[^1][i] = cell.Value.ToString(); i++; } } } return dtTable; }
3. 替换为轻量Excel读取库(性能再提升2~3倍)
如果开了AOT+代码优化后还是无法满足性能要求,推荐替换为纯读取的轻量库ExcelDataReader,该库无多余的编辑功能,专门针对读取速度做了优化,WASM下运行性能远高于ClosedXML。
使用方法:
- 先安装NuGet包:
ExcelDataReader、ExcelDataReader.DataSet - 工具方法替换为以下代码:
public static async Task<DataTable> GetDataTableFromExcel(IBrowserFile file) { using var stream = file.OpenReadStream(maxAllowedSize: 100 * 1024 * 1024); using var reader = ExcelReaderFactory.CreateOpenXmlReader(stream, new ExcelReaderConfiguration { LeaveOpen = false, DetectEncoding = true }); // 读取第一个工作表,第一行作为表头 var result = reader.AsDataSet(new DataSetConfiguration { UseHeaderRow = true }); return result.Tables[0]; }
4. 超大文件场景备选方案
如果需要处理10万行以上的超大Excel文件,可以通过JS互操作调用浏览器端的xlsx.js读取文件,JS处理二进制文件的性能在浏览器环境下优于当前WASM实现,读取完成后将JSON数组传递到C#端即可,全程无需上传服务端。
其他注意事项
- 你页面上仅展示前500行数据,可以在读取时限制最大读取行数,避免不必要的性能消耗
- 可以配合MudBlazor的
<MudProgressLinear>组件添加加载进度提示,优化用户体验
内容的提问来源于stack exchange,提问作者Waleed Al Harthi
相关产品推荐
相关产品推荐

