2014-02-20 4 views
1

Я использую библиотеку в проекте ASP.NET MVC для экспорта данных в CSV и обнаруживаю, что экспортированные данные либо обрезаются, либо, в случае меньших списков, нет данные записываются вообще, и я получаю пустой 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); 
       } 
      } 
     } 
    } 

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

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

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

Каков правильный способ использования этой библиотеки для правильного создания файлов 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, но получил сообщение об ошибке о потоке закрывается, и не обходил отладку это еще.

+0

Как и в сторону: Рассмотрите возможность использования фактических 'MemoryStream' объект для возврата из' File() '.. так что она становится 'FileStreamResult'. Это передается в браузер в куски и не выделяет большие объекты. –

+0

Эй это сообщение полезно, но как мы можем это сделать без MemoryStream? – DharaPPatel

ответ

6

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

Вариант 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); 
} 
+0

Я использую класс CsvFactory для CsvHelper, так немного другой, но textWriter.Flush() сделал трюк для меня! Благодаря! – Karl

+0

Nitpick, но в Option 2 вместо установки Position обратно в 0 вы можете просто использовать memoryStream.ToArray() в качестве первого параметра File(). – Djorge

Смежные вопросы