CsvHelper not writing anything to memory stream

C#Csvhelper

C# Problem Overview


I have the following method:

public byte[] WriteCsvWithHeaderToMemory<T>(IEnumerable<T> records) where T : class
{
    using (var memoryStream = new MemoryStream())
    using (var streamWriter = new StreamWriter(memoryStream))
    using (var csvWriter = new CsvWriter(streamWriter))
    {
        csvWriter.WriteRecords<T>(records);

        return memoryStream.ToArray();
    }
}

Which is being called with a list of objects - eventually from a database, but since something is not working I'm just populating a static collection. The objects being passed are as follows:

using CsvHelper.Configuration;

namespace Application.Models.ViewModels
{
    public class Model
    {
        [CsvField(Name = "Field 1", Ignore = false)]
        public string Field1 { get; set; }

        [CsvField(Name = "Statistic 1", Ignore = false)]
        public int Stat1{ get; set; }

        [CsvField(Name = "Statistic 2", Ignore = false)]
        public int Stat2{ get; set; }

        [CsvField(Name = "Statistic 3", Ignore = false)]
        public int Stat3{ get; set; }

        [CsvField(Name = "Statistic 4", Ignore = false)]
        public int Stat4{ get; set; }
    }
}

What I'm trying to do is write a collection to a csv for download in an MVC application. Every time I try to write to the method though, the MemoryStream is coming back with zero length and nothing being passed to it. I've used this before, but for some reason it's just not working - I'm somewhat confused. Can anyone point out to me what I've done wrong here?

Cheers

C# Solutions


Solution 1 - C#

You already have a using block which is great. That will flush your writer for you. You can just change your code slightly for it to work.

using (var memoryStream = new MemoryStream())
{
    using (var streamWriter = new StreamWriter(memoryStream))
    using (var csvWriter = new CsvWriter(streamWriter))
    {
        csvWriter.WriteRecords<T>(records);
    } // StreamWriter gets flushed here.

    return memoryStream.ToArray();
}

If you turn AutoFlush on, you need to be careful. This will flush after every write. If your stream is a network stream and over the wire, it will be very slow.

Solution 2 - C#

Put csvWriter.Flush(); before you return to flush the writer/stream.

EDIT: Per Jack's response. It should be the stream that gets flushed, not the csvWriter. streamWriter.Flush();. Leaving original solution, but adding this correction.

EDIT 2: My preferred answer is: https://stackoverflow.com/a/22997765/1795053 Let the using statements do the heavy lifting for you

Solution 3 - C#

Putting all these together (and the comments for corrections), including resetting the memory stream position, the final solution for me was;

        using (MemoryStream ms = new MemoryStream())
        {
            using (TextWriter tw = new StreamWriter(ms))
            using (CsvWriter csv = new CsvWriter(tw))
            {
                csv.WriteRecords(errors); // Converts error records to CSV

                tw.Flush(); // flush the buffered text to stream
                ms.Seek(0, SeekOrigin.Begin); // reset stream position

                Attachment a = new Attachment(ms, "errors.csv"); // Create attachment from the stream
                // I sent an email here with the csv attached.
            }
        }

In case the helps someone else!

Solution 4 - C#

There is no flush in csvWriter, the flush is in the streamWriter. When called

> csvWriter.Dispose();

it will flush the stream. Another approach is to set

> streamWriter.AutoFlush = true;

which will automatically flush the stream every time.

Solution 5 - C#

Here is working example:

void Main()
{
    var records = new List<dynamic>{
	   new { Id = 1, Name = "one" },
	   new { Id = 2, Name = "two" },
	};

    Console.WriteLine(records.ToCsv());
}

public static class Extensions {
    public static string ToCsv<T>(this IEnumerable<T> collection)
	{
    	using (var memoryStream = new MemoryStream())
	    {
		    using (var streamWriter = new StreamWriter(memoryStream))
			using (var csvWriter = new CsvWriter(streamWriter))
    		{
	    		csvWriter.WriteRecords(collection);
		    } // StreamWriter gets flushed here.

			return Encoding.ASCII.GetString(memoryStream.ToArray());
    	}
	}
}

Based on this answer.

Solution 6 - C#

using CsvHelper;
public class TwentyFoursStock
{
	[Name("sellerSku")]
	public string ProductSellerSku { get; set; }

	[Name("shippingPoint")]
	public string ProductShippingPoint { get; set; }
}

using (var writer = new StreamWriter("file.csv"))
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
	csv.WriteRecords(TwentyFoursStock);
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionIan CotterillView Question on Stackoverflow
Solution 1 - C#Josh CloseView Answer on Stackoverflow
Solution 2 - C#Eli GassertView Answer on Stackoverflow
Solution 3 - C#JoshView Answer on Stackoverflow
Solution 4 - C#TuomasKView Answer on Stackoverflow
Solution 5 - C#AmitView Answer on Stackoverflow
Solution 6 - C#Redhwan GhailanView Answer on Stackoverflow