【问题标题】:How to dynamically generate file for download in Razor Pages如何在 Razor 页面中动态生成文件以供下载
【发布时间】:2020-09-17 00:39:46
【问题描述】:

我想添加一个按钮,用于下载动态生成的 CSV 文件。

我认为我需要使用 FileStreamResult(或者可能是 FileContentResult),但我一直无法找到说明如何执行此操作的示例。

我看到了创建物理文件然后下载的示例。但我理想的解决方案是直接写入响应流,这比创建文件或首先在内存中构建字符串要高效得多。

有人见过在 Razor Pages(不是 MVC)中动态生成文件以供下载的示例吗?

【问题讨论】:

    标签: c# asp.net-core razor-pages


    【解决方案1】:

    这就是我想出的。

    标记:

    <a class="btn btn-success" asp-page-handler="DownloadCsv">
        Download CSV
    </a>
    

    处理程序:

    public IActionResult OnGetDownloadCsv()
    {
        using MemoryStream memoryStream = new MemoryStream();
        using CsvWriter writer = new CsvWriter(memoryStream);
    
        // Write to memoryStream using SoftCircuits.CsvParser
    
        writer.Flush(); // This is important!
    
        FileContentResult result = new FileContentResult(memoryStream.GetBuffer(), "text/csv")
        {
            FileDownloadName = "Filename.csv""
        };
        return result;
    }
    

    此代码有效,但我希望它更有效地使用内存。照原样,它将整个文件内容写入内存,然后将该内存复制到结果中。因此,在将任何内容写入响应流之前,一个大文件将在内存中存在两次。我对 FileStreamResult 很好奇,但无法让它发挥作用。

    如果有人可以对此进行改进,我很乐意将您的答案标记为已接受。

    更新:

    所以我意识到我可以修改上面的代码来使用FileStreamResult,方法是用这个替换最后一个块:

    memoryStream.Seek(0, SeekOrigin.Begin);
    FileStreamResult result = new FileStreamResult(memoryStream, "text/csv")
    {
        FileDownloadName = "Filename.csv"
    };
    return result;
    

    除了调用memoryStream.GetBuffer() 来复制所有字节之外,它的工作原理几乎相同,它只是传递内存流对象。这是一个改进,因为我没有不必要地复制字节。

    但是,缺点是我必须删除我的两个 using 语句,否则我会得到一个异常:

    ObjectDisposedException:无法访问已关闭的 Stream。

    看起来这是在额外复制字节或不清理我的流和 CSV 写入器之间进行权衡。

    最后,我能够防止 CSV 写入器在处理流时关闭它,并且由于 MemoryStream 没有非托管资源,因此保持打开状态应该没有害处。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-14
    • 1970-01-01
    • 2019-08-06
    • 1970-01-01
    • 2019-10-30
    • 2012-01-01
    • 1970-01-01
    相关资源
    最近更新 更多