Экспорт данных в CSV из контроллера

Я использую библиотеку CsvHelper в проекте ASP.NET MVC для экспорта данных в CSV и обнаруживаю, что экспортированные данные либо обрезаются, либо в случае небольших списков данные вообще не записываются, и я получаю пустой файл CSV.

У моего базового контроллера есть такой метод (который вызывается контроллерами, наследующими этот класс для экспорта списков объектов):

protected FileContentResult GetExportFileContentResult(IList data, string filename)
    {
        using (var memoryStream = new MemoryStream())
        {
            using (var streamWriter = new StreamWriter(memoryStream))
            {
                using (var csvWriter = new CsvWriter(streamWriter))
                {
                    csvWriter.WriteRecords(data);
                    return File(memoryStream.ToArray(), "text/csv", filename);
                }
            }
        }
    }

С экспортом списков 1k+ элементов кажется, что последние несколько элементов обрезаются. Если список элементов меньше ~100, возвращаемый файл CSV будет пустым и не содержит данных.

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

Также попытался удалить операторы использования в случае, если поток был удален слишком рано, но также не привел к каким-либо изменениям.

Как правильно использовать эту библиотеку для правильного создания файлов CSV (т. Е. Содержит все строки и работает независимо от размера списка)?

редактировать

Решил отказаться от использования CsvHelper и перешел с другой библиотекой под названием CsvTools. Это работает без проблем. Мой код ниже для справки.

protected FileContentResult GetExportFileContentResult(IList data, string filename)
{
    using (var memoryStream = new MemoryStream())
    {
            using (var streamWriter = new StreamWriter(memoryStream))
            {
                var dt = DataTable.New.FromEnumerable(data);
                dt.SaveToStream(streamWriter);
                return File(memoryStream.ToArray(), "text/csv", filename);
        }
    }
}

Кстати, попробовал предложенное Саймоном ниже предложение использовать поток памяти напрямую вместо вызова ToArray но получил ошибку о том, что поток закрыт, и пока не дошел до отладки.

1 ответ

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

Опция 1:

using (var memoryStream = new MemoryStream())
using (var streamWriter = new StreamWriter(memoryStream))
using (var csvWriter = new CsvWriter(streamWriter))
{
    csvWriter.WriteRecords(data);
    streamWriter.Flush();
    memoryStream.Position = 0;
    return File(memoryStream, "text/csv", filename);
}

Вариант 2:

using (var memoryStream = new MemoryStream())
{
    using (var streamWriter = new StreamWriter(memoryStream))
    using (var csvWriter = new CsvWriter(streamWriter))
    {
        csvWriter.WriteRecords(data);
    } // The stream gets flushed here.
    memoryStream.Position = 0;
    return File(memoryStream, "text/csv", filename);
}
Другие вопросы по тегам