Pascal Mariany
Pascal Mariany

Reputation: 77

How to write a C# List to CSV with CsvHelper package

I have a simple Console Application that contains a list of 3 users in Program.cs. Within Program.cs I want to call a method in FileOperations.cs.

First my Program.cs:

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using CsvHelper;

namespace GimpiesConsoleOOcsvListUI
{
    class Program
    {
        static void Main(string[] args)
        {
            // Create user default instances
            User user0 = new User("Beheer", "[email protected]", "123");
            User user1 = new User("Inkoop", "[email protected]", "123");
            User user2 = new User("Verkoop", "[email protected]", "123");

            // List of users (with a list you can add, get and remove items in the list)
            List<User> users = new List<User>();
            users.Add(user0);
            users.Add(user1);
            users.Add(user2);

            // Create login instance
            LoginManager loginMgr = new LoginManager();

            Start:
            // Welcome message
            Console.WriteLine("Welcome to GimpiesTerminal! Choose 1 to login or 2 to register:");

            // Get input from user
            string input = Console.ReadLine();

            bool successfull = false;

            while (!successfull)
            {
                if(input == "1")
                {
                    Console.WriteLine("Enter your username:");
                    string username = Console.ReadLine();
                    Console.WriteLine("Enter your password:");
                    string password = Console.ReadLine();

                    foreach (User user in users)
                    {
                        if (username == user.UserName && password == user.PassWord)
                            {
                                Console.WriteLine("You have successfully logged in !!!");
                                Console.ReadLine();
                                successfull = true;
                            break;  
                            }
                    }
                        if (!successfull)
                            {
                                Console.WriteLine("Your username or password is incorrect, try again !!!");
                            }
                }
                else if (input == "2")
                {
                        // Get user input
                        Console.WriteLine("Enter your username:");
                        string username = Console.ReadLine();

                        Console.WriteLine("Enter your email:");
                        string email = Console.ReadLine();

                        Console.WriteLine("Enter your password:");
                        string password = Console.ReadLine();

                        // Create fresh instance to save input in memory
                        User user = new User(username, email, password);

                        // Adds the user to the excisting list
                        users.Add(user);
                        
                        successfull = true;
                        goto Start;
                }
                else if (input == "3")
                {
                    // Here I want to call the method from FileOperations.cs to write the List here to a CSV file.
                }
                else
                {
                    Console.WriteLine("Try again !!!");
                    break;
                }
            }
            
            // // Loop over stored users within instances inside the list where users are added
            // foreach (User user in users)
            // {
            
            //     if(loginMgr.Login(user))
            //     {
            //         // Login successfull
            //         Console.WriteLine("Login user " + user.UserName);

            //     }
            //     else
            //     {
            //         // Not successfull

            //     }
            // }  
            
        }
    }
}

And here is my FileOperations.cs:

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using CsvHelper;

namespace GimpiesConsoleOOcsvListUI
{
    public class FileOperations
    {
        // Handles CRUD within CSV files and able to save them
        public void SaveToCSV(User user)
        {
            using (var mem = new MemoryStream())
            using (var writer = new StreamWriter(mem))
            using (var csvWriter = new CsvWriter(writer))
            {
                csvWriter.Configuration.Delimiter = ";";
                csvWriter.Configuration.HasHeaderRecord = true;
                csvWriter.Configuration.AutoMap<User>();

                csvWriter.WriteHeader<User>();
                csvWriter.WriteRecords(user);

                writer.Flush();
                var result = Encoding.UTF8.GetString(mem.ToArray());
                Console.WriteLine(result);
            }
        }
    } 
}

I get the following errors at line 16 of FileOperations.cs:

StreamWriter writer Argument 1: cannot convert from System.IO.StreamWriter to CsvHelper.ISerializer

And line 23:

User user Argument 1: cannot convert from GimpiesConsoleOOcsvListUI.User to System.Collections.IEnumerable

I'm new to C# so I hope you don't mind if it is a simple to solve problem! :-)

Upvotes: 1

Views: 13842

Answers (3)

msmolcic
msmolcic

Reputation: 6557

You could try the following piece of code if you want to serialize a single user object and display its serialized header and values:

public void SaveToCSV(List<User> users)
{
    var csvConfig = new CsvConfiguration(CultureInfo.CurrentCulture)
    {
        HasHeaderRecord = true,
        Delimiter = ",",
        Encoding = Encoding.UTF8
    };

    using (var mem = new MemoryStream())
    using (var writer = new StreamWriter(mem))
    using (var csvWriter = new CsvWriter(writer, csvConfig))
    {
        csvWriter.WriteRecords(users);

        writer.Flush();
        var result = Encoding.UTF8.GetString(mem.ToArray());
        Console.WriteLine(result);
    }
}

It is using a simple StringWriter instance needed by the library's CsvWriter and is using InvariantCulture info for content serialization. The third parameter leaveOpen must be set to true in this case because you're interested in the content of the StringWriter within the scope of the using block. Last but not least, you're currently passing a single instance of User so you have to call WriteRecord method instead of WriteRecords.

If you want to write it to the actual file though, you have to do it a bit differently:

public void SaveToCSV(List<User> users)
{
    var csvConfig = new CsvConfiguration(CultureInfo.CurrentCulture)
    {
        HasHeaderRecord = true,
        Delimiter = ",",
        Encoding = Encoding.UTF8
    };

    using (var writer = new StreamWriter(@"path\to\your\file.csv"))
    using (var csvWriter = new CsvWriter(writer, csvConfig))
    {
        csvWriter.WriteRecords(users);
    }
}

You don't need to call Flush in the second example because the end of using block calls it for you and you're not interested in the CSV content within its scope.

Upvotes: 2

Koder101
Koder101

Reputation: 892

Due to this change in csvhelper, the given examples won't work.

The updated code of @Jonathn would look like -

public void SaveToCSV(List<User> users)
    {
        var csvConfig = new CsvConfiguration(CultureInfo.CurrentCulture)
        {
            HasHeaderRecord = true,
            Delimiter = ",",
            Encoding = Encoding.UTF8
        };

        using (var mem = new MemoryStream())
        using (var writer = new StreamWriter(mem))
        using (var csvWriter = new CsvWriter(writer, csvConfig))
        {
            csvWriter.WriteHeader<User>();
            csvWriter.WriteRecords(users);

            writer.Flush();
            var result = Encoding.UTF8.GetString(mem.ToArray());
            Console.WriteLine(result);
        }
    }

Upvotes: 1

Jonathan Willcock
Jonathan Willcock

Reputation: 5245

You are getting the errors because you are passing the wrong parameter types in both cases. CsvWriter does not have a constructor which takes only one parameter being a TextWriter. I am not very familiar with this library, but I believe it may have done in the past. I suspect you have copied your code from previous examples on the internet, which are out of date.

The simple way to get around this is to add two more parameters thus:

using (var csvWriter = new CsvWriter(writer, CultureInfo.CurrentCulture, false))

The second error is because CsvWriter.WriteRecords expects an IEnumerable parameter, not a single instance. To fix this, you need to pass it your List<User>, so the whole code becomes:

public void SaveToCSV(List<User> users)
{
    using (var mem = new MemoryStream())
    using (var writer = new StreamWriter(mem))
    using (var csvWriter = new CsvWriter(writer, CultureInfo.CurrentCulture, false))
    {
        csvWriter.Configuration.Delimiter = ";";
                
        csvWriter.Configuration.HasHeaderRecord = true;
        csvWriter.Configuration.AutoMap<User>();

        csvWriter.WriteHeader<User>();
        csvWriter.WriteRecords(users);

        writer.Flush();
        var result = Encoding.UTF8.GetString(mem.ToArray());
        Console.WriteLine(result);
    }
}

Upvotes: 1

Related Questions