Экспорт данных в 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);
}