Ste*_*e W 4 c# closedxml blazor-server-side .net-6.0
在尝试使用 ClosedXML 构建 Excel 文件时,我遇到了一些有关内存流的意外行为。在调试器中,我可以看到 MemoryStream ms 正在由该wb.SaveAs()函数填充。但是,当直接将其传递到 时DotNetStreamReference,该文件将作为 0 字节的 blob 下载。
奇怪的是,当我将流转换为字节数组并返回流时,该函数按预期工作。
我在这里错过了一些基本的东西吗?
这是使用MS 示例得出的
技术:
C# 代码
async Task ExportToExcel()
{
string fileName = $"DocumentsExport{DateTime.UtcNow.Ticks}.xlsx";
var wb = new ClosedXML.Excel.XLWorkbook();
var ws = wb.AddWorksheet("Documents");
// construct headers
ws.Cell(1, 1).SetValue<string>("Document Name");
ws.Cell(1, 2).SetValue<string>("Description");
ws.Cell(1, 3).SetValue<string>("Sort Order");
ws.Cell(1, 4).SetValue<string>("Category Name");
ws.Cell(1, 5).SetValue<string>("Group Name");
ws.Cell(1, 6).SetValue<string>("Date Modified");
// construct worksheet contents
for (int i = 0; i < documents.Count; i++)
{
var document = documents[i];
int rowIndex = i + 2;
ws.Cell(rowIndex, 1).SetValue<string>(document.Name);
ws.Cell(rowIndex, 2).SetValue<string?>(document.Description);
ws.Cell(rowIndex, 3).SetValue<int?>(document.SortOrder);
ws.Cell(rowIndex, 4).SetValue<string>(document.DocumentCategory.Name);
ws.Cell(rowIndex, 5).SetValue<string>(document.DocumentCategory.DocumentGroup.Name);
ws.Cell(rowIndex, 6).SetValue<DateTime?>(document.DateModified);
}
// apply formatting and filters
ws.RangeUsed().SetAutoFilter();
ws.Columns().AdjustToContents();
// save file and convert to byte array
// passing this stream to the stream reference causes the file to be downloaded with 0 bytes, thus no content
using MemoryStream ms = new MemoryStream();
wb.SaveAs(ms);
// this line fails
//using var streamRef = new DotNetStreamReference(stream: ms);
// this line works
using var streamRef = new DotNetStreamReference(stream: new MemoryStream(ms.ToArray()));
// execute javaScript to download file
await JS.InvokeVoidAsync("downloadFileFromStream", fileName, streamRef);
}
Run Code Online (Sandbox Code Playgroud)
JavaScript 代码:
<script>
// script function used to download small files, like excel reports
// https://learn.microsoft.com/en-us/aspnet/core/blazor/file-downloads?view=aspnetcore-6.0
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 ?? '';
anchorElement.click();
anchorElement.remove();
URL.revokeObjectURL(url);
}
Run Code Online (Sandbox Code Playgroud)
您必须重置流位置。保存后,流位置位于流的末尾,当您传递该流时,其他方法从当前位置开始读取,因此没有任何内容可读取。ToArray从起始位置开始转换整个流,这就是为什么您可以看到所有数据。当您从该数组创建一个新数组时MemoryStream,它将拥有所有数据,但它的位置将位于开头,这就是它起作用的原因。
所以,你所要做的就是
using MemoryStream ms = new MemoryStream();
wb.SaveAs(ms);
ms.Position=0;
Run Code Online (Sandbox Code Playgroud)
它应该有效。