Streaming Excel Files from ASP.NET to the Client Browser
Directly transmittign an Excel workbook from an ASP.NET backend to a web client involves transforming object collections into tabular data, serializing the output to a memory buffer, and configuring the apropriate HTTP respnose headers.
public void ExportCollectionAsExcel<T>(IEnumerable<T> sourceCollection, string targetFileName)
{
var tabularData = ConvertToDataTable(sourceCollection);
if (tabularData == null || tabularData.Rows.Count == 0) return;
var workbookInstance = new XlsDocument();
var activeWorksheet = workbookInstance.Workbook.Worksheets.Add(targetFileName);
// Map column headers
for (int colIndex = 0; colIndex < tabularData.Columns.Count; colIndex++)
{
activeWorksheet.Cells.Add(1, colIndex + 1, tabularData.Columns[colIndex].ColumnName);
}
// Populate cell data
for (int rowIndex = 0; rowIndex < tabularData.Rows.Count; rowIndex++)
{
for (int colIndex = 0; colIndex < tabularData.Columns.Count; colIndex++)
{
var cellContent = tabularData.Rows[rowIndex][colIndex]?.ToString() ?? string.Empty;
activeWorksheet.Cells.Add(rowIndex + 2, colIndex + 1, cellContent);
}
}
using (var memoryStream = new MemoryStream())
{
workbookInstance.Save(memoryStream);
memoryStream.Position = 0;
var currentResponse = HttpContext.Current.Response;
currentResponse.Clear();
currentResponse.ContentType = "application/vnd.ms-excel";
currentResponse.ContentEncoding = Encoding.UTF8;
currentResponse.AppendHeader("Content-Disposition", $"attachment; filename={targetFileName}");
memoryStream.CopyTo(currentResponse.OutputStream);
currentResponse.End();
}
}
The covnersion utility maps public properties to a structured grid compatible with the XlsDocument API. Once the workbook is constructed and serialized into a MemoryStream, the HTTP response is cleared, assigned the Excel MIME type, and taggged with a Content-Disposition header to trigger a forced download.
Client-side execution requires a direct navigation request targeting the server endpoint:
window.open('/api/exports/download', '_blank');