Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why CsvHelper not reading from MemoryStream?

I am trying to convert an uploaded csv file to an object, so i can save in db. In the controller I am using CsvHeler

But looks like this only works if I first save the file and read from it. CsvHelper is not able to process the file contents directly from memory stream. In the code below the first GetRecords returns empty

    [HttpPost]
    [Route(ApiRoutes.EodVariationMarginPlugs)]
    public async Task<IActionResult> UploadPlugAsync(IFormFile filePayload)
    {

        if (filePayload.Length > 0)
        {

            using (var stream = new MemoryStream())
            {
                filePayload.CopyTo(stream);
                using (var reader = new StreamReader(stream))
                using (var csv = new CsvReader(reader))
                {
                    csv.Configuration.RegisterClassMap<EodVariationMarginPlugMap>();
                    csv.Configuration.MissingFieldFound = null;
                    var records = csv.GetRecords<EodVariationMarginPlug>().ToList(); // record count is 0
                    foreach (var p in records)
                    {
                        p.CreatedAt = DateTimeOffset.Now;
                        p.CreatedBy = HttpContext.User.Identity.Name;
                    }
                    await _repository.InsertPlugsAsync(records);
                }
            }

        var fileName = ContentDispositionHeaderValue
            .Parse(filePayload.ContentDisposition)
            .FileName.ToString().Trim('"');
            var path = Path.Combine(Path.GetTempPath(), fileName);
            using (var fileStream = new FileStream(path, FileMode.Create))
            {
                await filePayload.CopyToAsync(fileStream);
            }
            var textReader = System.IO.File.OpenText(path);
            using (var csv = new CsvReader(textReader))
            {
                csv.Configuration.RegisterClassMap<EodVariationMarginPlugMap>();
                csv.Configuration.MissingFieldFound = null;
                var records = csv.GetRecords<EodVariationMarginPlug>().ToList();
                foreach (var p in records)
                {
                    p.CreatedAt = DateTimeOffset.Now;
                    p.CreatedBy = HttpContext.User.Identity.Name;
                }
                await _repository.InsertPlugsAsync(records);
            }
        }
        return Ok();
    }
like image 928
Anand Avatar asked Mar 22 '18 17:03

Anand


1 Answers

The most common error here is forgetting MemoryStream is binary; it deals in bytes. You need something that deals in characters, which isn't always a 1:1 adaption. The good news is you avoided that error by wrapping the MemoryStream in a StreamReader:

using (var reader = new StreamReader(stream))

StreamReader implements TextReader, which works with characters rather than bytes. Yay! The bad news is the StreamReader is created right after this line:

filePayload.CopyTo(stream);

The problem was that line left the stream pointed at the end of the data. When you try to read from it, there's nothing left in the stream.

All you should need to do to fix this is seek back to the beginning. So this:

using (var stream = new MemoryStream())
{
    filePayload.CopyTo(stream);
    using (var reader = new StreamReader(stream))

Becomes this:

using (var stream = new MemoryStream())
{
    filePayload.CopyTo(stream);
    stream.Seek(0, SeekOrigin.Begin);

    using (var reader = new StreamReader(stream))
like image 198
Joel Coehoorn Avatar answered Sep 21 '22 17:09

Joel Coehoorn