Как динамически создавать файл для загрузки в Razor Pages - PullRequest
0 голосов
/ 29 мая 2020

Я хочу добавить кнопку, которая будет загружать динамически сгенерированный файл CSV.

Думаю, мне нужно использовать FileStreamResult (или, возможно, FileContentResult), но мне не удалось найти пример, показывает, как это сделать.

Я видел примеры, которые создают физический файл, а затем загружают его. Но мое идеальное решение было бы записывать непосредственно в поток ответа, что было бы намного эффективнее, чем создание файла или первое построение строки в памяти.

Кто-нибудь видел пример динамического создания файла для загрузки в Razor Страницы (не MVC)?

1 Ответ

0 голосов
/ 29 мая 2020

Вот что я придумал.

Разметка:

<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;
}

Этот код работает, но я с sh он использовал память более эффективно. Как есть, он записывает все содержимое файла в память, а затем копирует эту память в результат. Таким образом, большой файл будет существовать в памяти дважды, прежде чем что-либо будет записано в поток ответа. Мне было любопытно узнать о FileStreamResult, но мне не удалось заставить это работать.

Если кто-то сможет улучшить это, я с радостью помечу ваш ответ как принятый.

ОБНОВЛЕНИЕ:

Итак, я понял, что могу адаптировать приведенный выше код для использования FileStreamResult, заменив последний блок следующим:

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

Это работает почти так же, за исключением того, что вместо вызова memoryStream.GetBuffer() для копирования всех байтов он просто передает объект потока памяти. Это улучшение, поскольку я не копирую байты без необходимости.

Однако обратная сторона заключается в том, что мне нужно удалить два моих оператора using, иначе я получу исключение:

ObjectDisposedException: невозможно получить доступ к закрытому потоку.

Похоже, это компромисс между копированием байтов в дополнительное время или отсутствием очистки моих потоков и записи CSV.

В В конце концов, я могу запретить модулю записи CSV закрывать поток при его удалении, а поскольку MemoryStream не имеет неуправляемых ресурсов, не должно быть никакого вреда, если оставить его открытым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...