
如何在Blazor中使用IronXL导出 Excel 文件
**几乎所有Blazor Web 应用程序都需要将数据导出到 Excel,无论是生成销售报告、库存清单还是客户发票。**在Blazor Server 应用程序中,如何在不依赖 Microsoft Office 的情况下可靠地完成此操作可能令人望而却步。 IronXL让操作变得简单:您可以直接从服务器创建、格式化和下载 Excel 文件,无需安装 Office。 本指南将引导您使用IronXL在Blazor中构建一个可用于生产的 Excel 导出功能——从项目设置和服务设计到高级格式设置和多工作表报告。
如何在Blazor服务器项目中设置IronXL ?
在编写任何导出逻辑之前,您需要将IronXL添加到Blazor Server 项目并配置浏览器端下载助手。
创建Blazor服务器项目
首先在 Visual Studio 2022 或更高版本中创建一个新的Blazor Server 项目,目标框架为.NET 10。项目准备就绪后,通过NuGet程序包管理器控制台安装IronXL :
IronXL可与.NET 6 及更高版本配合使用,因此现有的Blazor项目无需升级框架即可采用它。 对于其他安装方法(例如NuGet UI 或 CLI),请参阅IronXL安装指南。
添加JavaScript下载助手
Blazor Server 在服务器端运行,因此触发文件下载需要一个小的JavaScript桥接程序。 在您的excelExport.js的文件:
window.downloadFileFromStream = async (fileName, contentStreamReference) => {
const arrayBuffer = await contentStreamReference.arrayBuffer();
const blob = new Blob([arrayBuffer]);
const url = URL.createObjectURL(blob);
const anchorElement = document.createElement('a');
anchorElement.href = url;
anchorElement.download = fileName ?? 'export.xlsx';
anchorElement.click();
anchorElement.remove();
URL.revokeObjectURL(url);
}
在您的_Host.cshtml文件中包含此脚本(或在.NET 8+中App.razor):
<script src="~/excelExport.js"></script>
此函数将Blazor的字节流转换为临时 blob URL,触发浏览器下载,然后清理 URL 对象以防止内存泄漏。 它的设计非常简洁——繁重的工作都是在服务器端用 C# 完成的。
如何在C#中创建Excel导出服务?
将 Excel 生成与Razor组件分离,可以保持代码的可测试性和跨多个页面的可重用性。 下面的示例将IronXL封装在一个专用的服务类中。
构建 ExcelExportService
创建一个新的文件Services/ExcelExportService.cs:
using IronXL;
using System.IO;
using ExportExcel.Models;
public class ExcelExportService
{
public byte[] GenerateSalesReport(List<SalesData> salesData)
{
var workbook = WorkBook.Create(ExcelFileFormat.XLSX);
workbook.Metadata.Author = "Sales Department";
var worksheet = workbook.CreateWorkSheet("Monthly Sales");
// Add column headers
worksheet["A1"].Value = "Date";
worksheet["B1"].Value = "Product";
worksheet["C1"].Value = "Quantity";
worksheet["D1"].Value = "Revenue";
worksheet["E1"].Value = "Profit Margin";
// Style the header row
var headerRange = worksheet["A1:E1"];
headerRange.Style.Font.Bold = true;
headerRange.Style.BackgroundColor = "#4472C4";
headerRange.Style.Font.Color = "#FFFFFF";
// Populate data rows
int row = 2;
foreach (var sale in salesData)
{
worksheet[$"A{row}"].Value = sale.Date.ToString("yyyy-MM-dd");
worksheet[$"B{row}"].Value = sale.Product ?? "Unknown";
worksheet[$"C{row}"].Value = sale.Quantity;
worksheet[$"D{row}"].Value = sale.Revenue;
worksheet[$"E{row}"].Value = $"=D{row}*0.15";
row++;
}
worksheet.AutoSizeColumn(0, true);
using var ms = workbook.ToStream();
return ms.ToArray();
}
}Imports IronXL
Imports System.IO
Imports ExportExcel.Models
Public Class ExcelExportService
Public Function GenerateSalesReport(salesData As List(Of SalesData)) As Byte()
Dim workbook = WorkBook.Create(ExcelFileFormat.XLSX)
workbook.Metadata.Author = "Sales Department"
Dim worksheet = workbook.CreateWorkSheet("Monthly Sales")
' Add column headers
worksheet("A1").Value = "Date"
worksheet("B1").Value = "Product"
worksheet("C1").Value = "Quantity"
worksheet("D1").Value = "Revenue"
worksheet("E1").Value = "Profit Margin"
' Style the header row
Dim headerRange = worksheet("A1:E1")
headerRange.Style.Font.Bold = True
headerRange.Style.BackgroundColor = "#4472C4"
headerRange.Style.Font.Color = "#FFFFFF"
' Populate data rows
Dim row As Integer = 2
For Each sale In salesData
worksheet($"A{row}").Value = sale.Date.ToString("yyyy-MM-dd")
worksheet($"B{row}").Value = If(sale.Product, "Unknown")
worksheet($"C{row}").Value = sale.Quantity
worksheet($"D{row}").Value = sale.Revenue
worksheet($"E{row}").Value = $"=D{row}*0.15"
row += 1
Next
worksheet.AutoSizeColumn(0, True)
Using ms = workbook.ToStream()
Return ms.ToArray()
End Using
End Function
End Class注册服务
将服务添加到Program.cs中的DI容器:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddScoped<ExcelExportService>();
var app = builder.Build();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();Imports Microsoft.AspNetCore.Builder
Imports Microsoft.Extensions.DependencyInjection
Dim builder = WebApplication.CreateBuilder(args)
builder.Services.AddRazorPages()
builder.Services.AddServerSideBlazor()
builder.Services.AddScoped(Of ExcelExportService)()
Dim app = builder.Build()
app.MapBlazorHub()
app.MapFallbackToPage("/_Host")
app.Run()该服务展示了IronXL 的几项关键功能。 可以通过单个方法调用创建新的工作簿和工作表,应用样式化的标题,从任何数据源填充行,并嵌入诸如=D2*0.15的Excel公式。 AutoSizeColumn调用确保列足够宽以正确显示其内容,无论数据长度如何。 有关更多格式选项,请参阅单元格样式指南。
如何从Blazor组件触发 Excel 下载?
服务部署完成后,你需要一个Razor组件来调用它并将生成的字节传递给浏览器。
编写Razor组件
在Pages/ExcelExportDashboard.razor创建一个页面:
@page "/excel-export"
@using ExportExcel.Models
@inject ExcelExportService ExcelService
@inject IJSRuntime JS
<h3>Excel Export Dashboard</h3>
<div class="export-section">
<button class="btn btn-primary" @onclick="ExportSalesReport" disabled="@isExporting">
@if (isExporting)
{
<span>Generating...</span>
}
else
{
<span>Export Sales Report</span>
}
</button>
@if (!string.IsNullOrEmpty(errorMessage))
{
<div class="alert alert-danger mt-2">@errorMessage</div>
}
</div>
@code {
private bool isExporting = false;
private string errorMessage = "";
private async Task ExportSalesReport()
{
try
{
isExporting = true;
errorMessage = "";
var salesData = GetSalesData();
var fileBytes = ExcelService.GenerateSalesReport(salesData);
using var stream = new MemoryStream(fileBytes);
using var streamRef = new DotNetStreamReference(stream);
await JS.InvokeVoidAsync(
"downloadFileFromStream",
$"SalesReport_{DateTime.Now:yyyyMMdd}.xlsx",
streamRef
);
}
catch (Exception)
{
errorMessage = "Export failed. Please try again.";
}
finally
{
isExporting = false;
}
}
private List<SalesData> GetSalesData()
{
return new List<SalesData>
{
new() { Date = DateTime.Now, Product = "Widget A", Quantity = 100, Revenue = 5000 },
new() { Date = DateTime.Now.AddDays(-1), Product = "Widget B", Quantity = 75, Revenue = 3750 }
};
}
}Imports ExportExcel.Models
Imports Microsoft.JSInterop
@page "/excel-export"
@inject ExcelExportService ExcelService
@inject IJSRuntime JS
<h3>Excel Export Dashboard</h3>
<div class="export-section">
<button class="btn btn-primary" @onclick="ExportSalesReport" disabled="@isExporting">
@If isExporting Then
<span>Generating...</span>
Else
<span>Export Sales Report</span>
End If
</button>
@If Not String.IsNullOrEmpty(errorMessage) Then
<div class="alert alert-danger mt-2">@errorMessage</div>
End If
</div>
@code {
Private isExporting As Boolean = False
Private errorMessage As String = ""
Private Async Function ExportSalesReport() As Task
Try
isExporting = True
errorMessage = ""
Dim salesData = GetSalesData()
Dim fileBytes = ExcelService.GenerateSalesReport(salesData)
Using stream As New MemoryStream(fileBytes)
Using streamRef As New DotNetStreamReference(stream)
Await JS.InvokeVoidAsync(
"downloadFileFromStream",
$"SalesReport_{DateTime.Now:yyyyMMdd}.xlsx",
streamRef
)
End Using
End Using
Catch ex As Exception
errorMessage = "Export failed. Please try again."
Finally
isExporting = False
End Try
End Function
Private Function GetSalesData() As List(Of SalesData)
Return New List(Of SalesData) From {
New SalesData() With {.Date = DateTime.Now, .Product = "Widget A", .Quantity = 100, .Revenue = 5000},
New SalesData() With {.Date = DateTime.Now.AddDays(-1), .Product = "Widget B", .Quantity = 75, .Revenue = 3750}
}
End Function
}组件的功能
isExporting标志在生成期间禁用按钮,防止重复请求。 SalesReport_20260228.xlsx无需额外配置即可保持下载的有序。
当您在浏览器中导航到/excel-export时,仪表板页面将加载一个导出按钮:

点击按钮后会生成电子表格,浏览器会自动下载该文件:

您可以对 Excel 导出文件应用哪些高级格式?
基本数据导出功能可以满足许多使用场景,但生产应用通常需要条件格式、多个工作表或数据验证。 IronXL原生支持所有这些功能。
库存报告的条件格式
以下服务会将库存不足的商品以红色突出显示——这是仓库或库存管理应用程序的常见要求:
using IronXL;
using ExportExcel.Models;
using System.IO;
public class InventoryExportService
{
public byte[] GenerateInventoryReport(List<InventoryItem> items)
{
var workbook = WorkBook.Create();
var details = workbook.CreateWorkSheet("Inventory Details");
// Column headers
details["A1"].Value = "SKU";
details["B1"].Value = "Name";
details["C1"].Value = "Quantity";
details["D1"].Value = "Reorder Level";
details["E1"].Value = "Status";
var headerRange = details["A1:E1"];
headerRange.Style.Font.Bold = true;
headerRange.Style.BackgroundColor = "#2E75B6";
headerRange.Style.Font.Color = "#FFFFFF";
for (int i = 0; i < items.Count; i++)
{
int row = i + 2;
var item = items[i];
details[$"A{row}"].Value = item.SKU;
details[$"B{row}"].Value = item.Name;
details[$"C{row}"].Value = item.Quantity;
details[$"D{row}"].Value = item.ReorderLevel;
details[$"E{row}"].Value = item.Quantity < item.ReorderLevel
? "Reorder Required"
: "OK";
if (item.Quantity < item.ReorderLevel)
{
// Highlight the entire row for low-stock items
details[$"A{row}:E{row}"].Style.BackgroundColor = "#FFB6B6";
details[$"C{row}"].Style.Font.Bold = true;
}
}
details.AutoSizeColumn(0, true);
details.AutoSizeColumn(1, true);
using var stream = workbook.ToStream();
return stream.ToArray();
}
}Imports IronXL
Imports ExportExcel.Models
Imports System.IO
Public Class InventoryExportService
Public Function GenerateInventoryReport(items As List(Of InventoryItem)) As Byte()
Dim workbook = WorkBook.Create()
Dim details = workbook.CreateWorkSheet("Inventory Details")
' Column headers
details("A1").Value = "SKU"
details("B1").Value = "Name"
details("C1").Value = "Quantity"
details("D1").Value = "Reorder Level"
details("E1").Value = "Status"
Dim headerRange = details("A1:E1")
headerRange.Style.Font.Bold = True
headerRange.Style.BackgroundColor = "#2E75B6"
headerRange.Style.Font.Color = "#FFFFFF"
For i As Integer = 0 To items.Count - 1
Dim row As Integer = i + 2
Dim item = items(i)
details($"A{row}").Value = item.SKU
details($"B{row}").Value = item.Name
details($"C{row}").Value = item.Quantity
details($"D{row}").Value = item.ReorderLevel
details($"E{row}").Value = If(item.Quantity < item.ReorderLevel, "Reorder Required", "OK")
If item.Quantity < item.ReorderLevel Then
' Highlight the entire row for low-stock items
details($"A{row}:E{row}").Style.BackgroundColor = "#FFB6B6"
details($"C{row}").Style.Font.Bold = True
End If
Next
details.AutoSizeColumn(0, True)
details.AutoSizeColumn(1, True)
Using stream = workbook.ToStream()
Return stream.ToArray()
End Using
End Function
End ClassIronXL会在生成数据时根据数据值应用单元格级别的格式设置。您还可以以声明方式应用条件格式规则,或在同一工作簿中管理多个工作表——例如,一个工作表用于显示当前库存,另一个工作表用于显示历史订单。
将多个工作表添加到单个导出文件中
将数据分成逻辑表格可以提高可读性,而无需单独下载:
public byte[] GenerateMultiSheetReport(
List<SalesData> sales,
List<InventoryItem> inventory)
{
var workbook = WorkBook.Create(ExcelFileFormat.XLSX);
// Sheet 1 -- Sales summary
var salesSheet = workbook.CreateWorkSheet("Sales");
salesSheet["A1"].Value = "Date";
salesSheet["B1"].Value = "Revenue";
salesSheet["A1:B1"].Style.Font.Bold = true;
for (int i = 0; i < sales.Count; i++)
{
salesSheet[$"A{i + 2}"].Value = sales[i].Date.ToString("yyyy-MM-dd");
salesSheet[$"B{i + 2}"].Value = sales[i].Revenue;
}
// Sheet 2 -- Inventory snapshot
var invSheet = workbook.CreateWorkSheet("Inventory");
invSheet["A1"].Value = "SKU";
invSheet["B1"].Value = "Name";
invSheet["C1"].Value = "Quantity";
invSheet["A1:C1"].Style.Font.Bold = true;
for (int i = 0; i < inventory.Count; i++)
{
invSheet[$"A{i + 2}"].Value = inventory[i].SKU;
invSheet[$"B{i + 2}"].Value = inventory[i].Name;
invSheet[$"C{i + 2}"].Value = inventory[i].Quantity;
}
using var stream = workbook.ToStream();
return stream.ToArray();
}Public Function GenerateMultiSheetReport( _
sales As List(Of SalesData), _
inventory As List(Of InventoryItem)) As Byte()
Dim workbook = WorkBook.Create(ExcelFileFormat.XLSX)
' Sheet 1 -- Sales summary
Dim salesSheet = workbook.CreateWorkSheet("Sales")
salesSheet("A1").Value = "Date"
salesSheet("B1").Value = "Revenue"
salesSheet("A1:B1").Style.Font.Bold = True
For i As Integer = 0 To sales.Count - 1
salesSheet($"A{i + 2}").Value = sales(i).Date.ToString("yyyy-MM-dd")
salesSheet($"B{i + 2}").Value = sales(i).Revenue
Next
' Sheet 2 -- Inventory snapshot
Dim invSheet = workbook.CreateWorkSheet("Inventory")
invSheet("A1").Value = "SKU"
invSheet("B1").Value = "Name"
invSheet("C1").Value = "Quantity"
invSheet("A1:C1").Style.Font.Bold = True
For i As Integer = 0 To inventory.Count - 1
invSheet($"A{i + 2}").Value = inventory(i).SKU
invSheet($"B{i + 2}").Value = inventory(i).Name
invSheet($"C{i + 2}").Value = inventory(i).Quantity
Next
Using stream = workbook.ToStream()
Return stream.ToArray()
End Using
End Function有关涵盖工作簿属性、范围操作和图表支持的完整 API 参考,请访问IronXL API 文档。

如何高效地处理错误和大型数据集?
当数据集很大时,Excel导出操作可能会静默失败或降低性能。 以下模式可以解决这两个问题。
服务层中的错误处理
将生成逻辑封装在服务(而不是组件)中,可以确保所有调用者的错误处理保持一致。 推荐的做法是让IronXL异常传播,然后将其包装在特定领域的异常中,并包含有关哪个报告失败的上下文:
在InvalidOperationException("Failed to generate sales report", ex)。 在Blazor组件中,捕获InvalidOperationException并显示友好的用户消息,而不透露内部细节。 使用注入到服务构造函数中的ILogger<t>记录内部异常,以便开发团队可以追踪到特定的工作簿操作失败。 永远不要向最终用户显示原始异常消息——文件路径、内存地址或堆栈跟踪可能会泄露服务器内部信息。
有关Blazor中结构化错误日志记录的指导,请参阅 Microsoft 官方文档中的错误处理最佳实践。 有关在.NET中构建可测试服务的更多指南,Microsoft的依赖注入文档解释了如何注册和解析范围服务,这正是这里使用的模式和ExcelExportService。
大型数据集的性能考量
对于超过几千行的数据集,可以考虑以下方法:
| 翻译策略 | 何时使用 | IronXL支持 |
|---|---|---|
| 直接流式传输响应 | Files >10 MB | workbook.ToStream() |
| 导出前对数据进行分页 | 带筛选器的 UI 驱动导出 | 在创建工作簿之前申请服务 |
| 背景工作 + 下载链接 | Reports taking >5 seconds | 结合 SignalR 或轮询方式 |
| 在大工作表上禁用自动调整列宽 | Sheets with >500 rows | 设置固定列宽 |
IronXL的ToStream()方法直接写入输出流,而不需先将整个文件加载到字节数组中,这对于大型工作簿保持低内存使用率。 有关额外性能指导,请参阅使用IronXL读取和写入大Excel文件。
IronXL还支持哪些 Excel 功能?
除了基本的导出功能外, IronXL还提供了一系列 Excel 功能,可满足实际的报告需求。
公式、命名区域和数字格式设置
您可以使用与直接在单元格中输入相同的语法嵌入任何 Excel 公式。 IronXL在读取时计算公式,因此生成文件的使用者在打开电子表格后即可看到计算结果。 命名范围使公式更易读、更易于维护:
// Aggregate formulas on a summary row
worksheet["E2"].Value = "=SUM(D2:D100)";
worksheet["F2"].Value = "=AVERAGE(C2:C100)";
worksheet["G2"].Value = "=COUNTIF(B2:B100,\"Widget A\")";
// Named ranges improve formula readability
worksheet["D2:D100"].Name = "RevenueColumn";
worksheet["E2"].Value = "=SUM(RevenueColumn)";
// Number and date formatting prevents type misinterpretation
worksheet["D2"].Value = 12345.67m;
worksheet["D2"].FormatString = "#,##0.00";
worksheet["A2"].Value = DateTime.Now;
worksheet["A2"].FormatString = "dd/MM/yyyy";' Aggregate formulas on a summary row
worksheet("E2").Value = "=SUM(D2:D100)"
worksheet("F2").Value = "=AVERAGE(C2:C100)"
worksheet("G2").Value = "=COUNTIF(B2:B100,""Widget A"")"
' Named ranges improve formula readability
worksheet("D2:D100").Name = "RevenueColumn"
worksheet("E2").Value = "=SUM(RevenueColumn)"
' Number and date formatting prevents type misinterpretation
worksheet("D2").Value = 12345.67D
worksheet("D2").FormatString = "#,##0.00"
worksheet("A2").Value = DateTime.Now
worksheet("A2").FormatString = "dd/MM/yyyy"要定义命名范围并显式设置数字格式,IronXL将两者都作为范围对象的属性公开。 这样可以防止 Excel 将货币值视为纯文本——这是从以字符串形式存储值的数据库导出财务数据时常见的问题。
支持的Excel文件格式
IronXL可以读写多种Excel格式,包括.tsv。 格式在保存时确定,因此同一个服务类只需稍作参数更改即可支持 Excel 和 CSV 导出:
// Export as CSV for systems that consume flat files
workbook.SaveAs("report.csv");
// Or stream as CSV for download
using var ms = workbook.ToStream(ExcelFileFormat.CSV);' Export as CSV for systems that consume flat files
workbook.SaveAs("report.csv")
' Or stream as CSV for download
Using ms As Stream = workbook.ToStream(ExcelFileFormat.CSV)
End Using这种灵活性在集成过程中非常重要,因为下游系统(如 ERP 平台或数据仓库)需要特定的文件格式。 要全面比较IronXL和其他 Excel 库的功能,请访问IronXL功能页面。
如果您需要在调试意外输出时了解.xlsx文件的内部结构,Microsoft提供了一个很好的参考用于理解OOXML文件格式。 IronXL的NuGet包也已在NuGet上列出,并附有完整的版本历史记录和兼容性说明。
如何开始使用IronXL进行Blazor项目?
IronXL提供免费的开发许可,您可以不受任何时间限制地进行构建和测试。 生产环境应用需要部署许可证。
您可以直接从NuGet下载免费试用版——无需注册即可开始使用。 准备部署时,请查看IronXL许可选项,找到适合应用程序规模的方案。
IronXL适用于所有主流的.NET应用程序类型,包括Blazor Server、 Blazor WebAssembly(服务器端渲染)、 ASP.NET Core MVC、控制台应用程序和 Windows 桌面应用程序。该库面向.NET Standard 2.0,因此兼容从.NET Framework 4.6.2 到.NET 10 的所有受支持.NET版本。如果项目还需要生成 PDF 文件, IronPDF可以与IronXL无缝集成,允许您从同一服务层将数据导出为 Excel 或 PDF 格式。
要了解更多 Blazor 特定示例,请参阅Blazor Excel 导出教程和ASP.NET Core导出指南。 对于读取现有电子表格, C# Excel 读取器教程涵盖了常见的导入场景。 您还可以了解如何从头开始创建新的 Excel 工作簿,以用于需要以编程方式而不是从模板构建文件的项目。

Curtis Chau 拥有卡尔顿大学的计算机科学学士学位,专注于前端开发,精通 Node.js、TypeScript、JavaScript 和 React。他热衷于打造直观且美观的用户界面,喜欢使用现代框架并创建结构良好、视觉吸引力强的手册。
相关文章



