How to Export Excel Files in Blazor Using IronXL
Exporting data to Excel is something almost every Blazor web application needs -- whether you are generating sales reports, inventory lists, or customer invoices. In a Blazor Server application, accomplishing this reliably without requiring Microsoft Office can feel daunting. IronXL makes it straightforward: you can create, format, and download Excel files directly from the server, with no Office installation required. This guide walks you through building a production-ready Excel export feature in Blazor using IronXL -- from project setup and service design to advanced formatting and multi-sheet reports.
How Do You Set Up IronXL in a Blazor Server Project?
Before writing any export logic, you need to add IronXL to a Blazor Server project and configure a browser-side download helper.
Creating the Blazor Server Project
Start by creating a new Blazor Server project in Visual Studio 2022 or later, targeting .NET 10. Once the project is ready, install IronXL through the NuGet Package Manager Console:
Install-Package IronXL.Excel
IronXL works with .NET 6 and later, so existing Blazor projects can adopt it without upgrading the framework. For alternative installation methods -- such as the NuGet UI or CLI -- see the IronXL installation guide.
Adding the JavaScript Download Helper
Blazor Server runs on the server side, so triggering a file download requires a small JavaScript bridge. In your wwwroot folder, add a file called 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);
}
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);
}
Include this script in your _Host.cshtml file (or App.razor in .NET 8+):
<script src="~/excelExport.js"></script>
<script src="~/excelExport.js"></script>
This function converts the byte stream from Blazor into a temporary blob URL, triggers the browser download, then cleans up the URL object to prevent memory leaks. It is intentionally minimal -- the heavy lifting happens in C# on the server.
How Do You Create an Excel Export Service in C#?
Separating Excel generation from your Razor components keeps the code testable and reusable across multiple pages. The pattern below wraps IronXL inside a dedicated service class.
Building the ExcelExportService
Create a new file 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();
}
}
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
Registering the Service
Add the service to the DI container in Program.cs:
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();
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()
This service demonstrates several key IronXL capabilities. You can create new workbooks and worksheets with a single method call, apply styled headers, populate rows from any data source, and embed Excel formulas such as =D2*0.15. The AutoSizeColumn call ensures columns are wide enough to display their content correctly, regardless of data length. For further formatting options, see the cell styling guide.
How Do You Trigger an Excel Download from a Blazor Component?
Once the service is in place, you need a Razor component that calls it and passes the resulting bytes to the browser.
Writing the Razor Component
Create a page at 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 }
};
}
}
@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
}
What the Component Does
The isExporting flag disables the button during generation, preventing duplicate requests. The DotNetStreamReference wrapper handles efficient binary streaming from the .NET memory stream to the JavaScript function -- avoiding large base64 strings that would inflate payload size. Timestamped filenames such as SalesReport_20260228.xlsx keep downloads organized without additional configuration.
When you navigate to /excel-export in the browser, the dashboard page loads with an export button:

Clicking the button generates the spreadsheet and the browser automatically downloads the file:

What Advanced Formatting Can You Apply to Excel Exports?
Basic data exports satisfy many use cases, but production applications often need conditional formatting, multiple worksheets, or data validation. IronXL supports all of these natively.
Conditional Formatting for Inventory Reports
The following service highlights low-stock items in red -- a common requirement for warehouse or inventory management applications:
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();
}
}
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 Class
IronXL applies cell-level formatting based on data values at generation time. You can also apply conditional formatting rules declaratively, or manage multiple worksheets within the same workbook -- for example, one sheet for current stock and another for historical orders.
Adding Multiple Worksheets to a Single Export
Separating data into logical sheets improves readability without requiring separate downloads:
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 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
For a full API reference covering workbook properties, range operations, and chart support, visit the IronXL API documentation.

How Do You Handle Errors and Large Datasets Efficiently?
Excel export operations can fail silently or degrade performance when datasets are large. The patterns below address both concerns.
Error Handling in the Service Layer
Wrapping generation logic in the service (rather than the component) keeps error handling consistent across all callers. The recommended pattern is to let IronXL exceptions propagate, then wrap them in a domain-specific exception with context about which report failed:
Place a try/catch block around the workbook generation in GenerateSalesReport, catching Exception and rethrowing as InvalidOperationException("Failed to generate sales report", ex). In the Blazor component, catch the InvalidOperationException and display a user-friendly message without exposing internal details. Log the inner exception using ILogger<T> injected into the service constructor, so the development team can trace failures back to a specific workbook operation. Never surface raw exception messages to end users -- file paths, memory addresses, or stack traces can reveal server internals.
See error handling best practices in the official Microsoft documentation for guidance on structured error logging in Blazor. For more guidance on building testable services in .NET, the Microsoft dependency injection documentation explains how to register and resolve scoped services, which is exactly the pattern used here with ExcelExportService.
Performance Considerations for Large Datasets
For datasets exceeding a few thousand rows, consider these approaches:
| Strategy | When to Use | IronXL Support |
|---|---|---|
| Stream directly to response | Files >10 MB | workbook.ToStream() |
| Paginate data before export | UI-driven exports with filters | Apply in service before creating workbook |
| Background job + download link | Reports taking >5 seconds | Combine with SignalR or polling |
| Disable AutoSizeColumn on large sheets | Sheets with >500 rows | Set fixed column widths instead |
IronXL's ToStream() method writes directly to an output stream without loading the entire file into a byte array first, which keeps memory usage lower for large workbooks. For additional performance guidance, see reading and writing large Excel files with IronXL.
What Other Excel Features Does IronXL Support?
Beyond basic export, IronXL provides a wide range of Excel features that cover real-world reporting requirements.
Formulas, Named Ranges, and Number Formatting
You can embed any Excel formula using the same syntax you would type directly into a cell. IronXL evaluates formulas at read time, so consumers of the generated file see calculated results as soon as they open the spreadsheet. Named ranges make formulas more readable and maintainable over time:
// 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.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"
To define named ranges and set the number format explicitly, IronXL exposes both as properties on the range object. This prevents Excel from treating currency values as plain text -- a common issue when exporting financial data from databases that store values as strings.
Supported Excel File Formats
IronXL can read and write multiple Excel formats including .xlsx, .xls, .csv, and .tsv. The format is determined at save time, so the same service class can support both Excel and CSV exports with a small parameter change:
// 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 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
This flexibility matters in integrations where downstream systems -- such as ERP platforms or data warehouses -- expect a specific file format. For a full feature comparison between IronXL and other Excel libraries, visit the IronXL features page.
Microsoft provides a good reference for understanding OOXML file formats if you need to understand the internal structure of .xlsx files when debugging unexpected output. The NuGet package for IronXL is also listed on NuGet.org with full version history and compatibility notes.
How Do You Get Started with IronXL for Blazor Projects?
IronXL is available under a free development license that lets you build and test without any time limit. For production applications, a deployment license is required.
You can download a free trial directly from NuGet -- no registration is needed to start. When you are ready to deploy, review the IronXL licensing options to find the plan that fits the scale of the application.
IronXL works across all major .NET application types -- Blazor Server, Blazor WebAssembly (server-rendered), ASP.NET Core MVC, console applications, and Windows desktop apps. The library targets .NET Standard 2.0, so it is compatible with every supported .NET version from .NET Framework 4.6.2 through .NET 10. If the project also requires PDF generation, IronPDF integrates alongside IronXL with no conflicts, allowing you to export data as either Excel or PDF from the same service layer.
To explore more Blazor-specific examples, see the Blazor Excel export tutorial and the ASP.NET Core export guide. For reading existing spreadsheets, the C# Excel reader tutorial covers common import scenarios. You can also review how to create a new Excel workbook from scratch for projects that need to build files programmatically rather than from templates.
Frequently Asked Questions
How can I export data to Excel in Blazor Server apps?
You can use IronXL to export data to Excel in Blazor Server apps. IronXL allows you to create, format, and download Excel files directly from the server without needing Microsoft Office.
Do I need Microsoft Office installed to use IronXL in Blazor?
No, you do not need Microsoft Office installed. IronXL allows you to handle Excel files in Blazor Server apps independently of Microsoft Office.
Can I format Excel files using IronXL in Blazor applications?
Yes, IronXL provides tools to format Excel files, allowing you to customize the appearance of your data directly from your Blazor Server app.
Is IronXL compatible with Blazor Server applications?
Yes, IronXL seamlessly integrates with Blazor Server applications, enabling easy export and handling of Excel files.
What are the benefits of using IronXL for Excel export in Blazor?
IronXL offers a straightforward way to create and manipulate Excel files without requiring Office, making it an efficient solution for exporting data in Blazor apps.
Can IronXL handle large Excel files in Blazor Server apps?
Yes, IronXL is designed to handle large Excel files efficiently within Blazor Server applications.
What types of Excel files can I create with IronXL in a Blazor app?
With IronXL, you can create various types of Excel files, including XLSX, XLS, and CSV, directly in your Blazor application.
Is it possible to download Excel files from a Blazor Server app using IronXL?
Yes, IronXL supports downloading Excel files directly from a Blazor Server app, providing a seamless experience for end-users.
How does IronXL improve Excel export functionality in Blazor compared to other solutions?
IronXL simplifies the process of exporting Excel files in Blazor by eliminating the need for Microsoft Office and integrating directly with your server application.
What makes IronXL a good choice for Blazor developers?
IronXL is a good choice for Blazor developers because it offers robust Excel handling capabilities, doesn't require Office installation, and integrates easily into Blazor Server apps.




