Generate a CSV from a generic list of objects using reflection and extension methods

Download the source code for this post: ReflectionCSV.zip

Last week I wrote a post about generating a CSV from a DataTable. As I hardly use DataTables these days I thought it would be good to write a function that does this for a generic list of objects using reflection to get the properties of the object and export them.

In this example I have done this using an extension method on the generic list. This approach could also be easily applied to the DataTable example.

First I have created a basic object called Person:

public class Person
{
    public string Forename { get; set; }
    public string Surname { get; set; }
    public int Age { get; set; }
}

The next step was to create the extension method on the generic list to generate the CSV data.  It works very much like the method to create the CSV data from the DataTable, but it uses reflection to get the properties for the object type, then iterates through the list to get the values for each property.


using System.Text;
using System.Reflection;

public static class Extensions
{
    public static string GetCSV<T>(this List<T> list)
    {
        StringBuilder sb = new StringBuilder();

        //Get the properties for type T for the headers
        PropertyInfo[] propInfos = typeof(T).GetProperties();
        for (int i = 0; i <= propInfos.Length - 1; i++)
        {
            sb.Append(propInfos[i].Name);

            if (i < propInfos.Length - 1)
            {
                sb.Append(",");
            }
        }

        sb.AppendLine();

        //Loop through the collection, then the properties and add the values
        for (int i = 0; i <= list.Count - 1; i++)
        {
            T item = list[i];
            for (int j = 0; j <= propInfos.Length - 1; j++)
            {
                object o = item.GetType().GetProperty(propInfos[j].Name).GetValue(item, null);
                if (o != null)
                {
                    string value = o.ToString();

                    //Check if the value contans a comma and place it in quotes if so
                    if (value.Contains(","))
                    {
                        value = string.Concat("\"", value, "\"");
                    }

                    //Replace any \r or \n special characters from a new line with a space
                    if (value.Contains("\r"))
                    {
                        value = value.Replace("\r", " ");
                    }
                    if (value.Contains("\n"))
                    {
                        value = value.Replace("\n", " ");
                    }

                    sb.Append(value);
                }

                if (j < propInfos.Length - 1)
                {
                    sb.Append(",");
                }
            }

            sb.AppendLine();
        }

        return sb.ToString();
    }
}

This method can be used to get the CSV string data, and then passed to the following method which I have placed in a static class called CSVHelper:

public static class CSVHelper
{
    public static void ExportCSV(string csv, string filename)
    {
        HttpContext.Current.Response.Clear();
        HttpContext.Current.Response.AddHeader("content-disposition", string.Format("attachment; filename={0}.csv", filename));
        HttpContext.Current.Response.ContentType = "text/csv";
        HttpContext.Current.Response.AddHeader("Pragma", "public");
        HttpContext.Current.Response.Write(csv);
        HttpContext.Current.Response.End();
    }
}

I have added an second extension method which calls GetCSV and ExportCSV so that exporting can be done in a single line, but GetCSV can also be used on it’s own if some other processing is required before exporting:

public static void ExportCSV<T>(this List<T> list, string filename)
{
    string csv = GetCSV(list);
    CSVHelper.ExportCSV(csv, filename);
}

Finally I have created a button on my form to create a new list of Person and export the CSV.  I have also added  a label to display any errors:


protected void btnExport_Click(object sender, EventArgs e)
{
    try
    {
        List<Person> people = GetPeople();
        people.ExportCSV("myCSV");
    }
    catch (System.Threading.ThreadAbortException)
    {
        //Thrown then calling Response.End in CSV Helper
    }
    catch(Exception ex)
    {
        lblMessage.Text = string.Concat("An error occurred: ", ex.Message);
    }
}

private List<Person> GetPeople()
{
    return new List<Person>()
    {
        new Person() {Forename = "Joe", Surname="Stevens", Age=26 },
        new Person() {Forename = "Emily", Surname="Stevens", Age=28 },
        new Person() {Forename = "John", Surname="Glazebrook", Age=34 },
        new Person() {Forename = "Sylvain", Surname="Whissell", Age=37 },
        new Person() {Forename = "Leroy", Surname="Phipps", Age=26 }
    };
}

Now any generic list has the GetCSV and ExportCSV methods that will generate a CSV for the objects in the list.

Download the source code for this post: ReflectionCSV.zip

Posted on by Joe in ASP.NET, C#

16 Responses to Generate a CSV from a generic list of objects using reflection and extension methods

  1. Tal

    Hi,
    Where can I find example of Export List to CSV in C# for Console Application?
    Thanks,
    Tal

  2. Joe

    Hi Tal

    The code in this post should work fine in a console app.

    Joe

  3. Shay Jacoby

    Hi. thanks, very good and useful code.
    I did 2 changes:
    1. Changed List arg type to IList
    2. Converted ExportCSV to extension like:
    public static void AsCSVResponse(this string csv, string filename)
    {…}
    Thx ext. does the same work but now I call CSV EXport like:
    GetCSV(list).AsCSVResponse(filename);

    and from client:
    myList.ExportCSV(“myCSV”);

  4. Ed

    Thanks Joe. Great concept – simple & effective. Just what I was looking for.

  5. daoming

    great post, you have saved my days.

    many thanks.

  6. Justin

    Great work! Thanks for sharing.

  7. Grant

    Thanks Joe. We’ve had an old procedure for exporting datatables to csv for some time, but we’re moving to lists of strongly-typed objects so I needed a new procedure… this works great!

  8. Joe

    Glad it helped Grant

    Cheers
    Joe

  9. Pandiarajan

    Really works fine and helpful

  10. kris

    Thanks for the great Concept

  11. Manj

    Good Work Joe! Very close to what I was looking for. Even better that it’s an extension method. I just had to add in another parameter for fields to exclude from the csv.
    and converted the propInfos to a List so I could remove those fields.

    lstPropInfos.RemoveAll(pi => exclusionList.Any(el => el.ToString() == pi.Name));

    Thanks!
    Manj

  12. dswayne

    Great solution. Exactly what I needed!

  13. surendra

    Simple and Great, Thanks a lot.

  14. Menol

    Thank you very much for the article and specially very clean source code! you definitely saved me a lot of time today.

  15. DDyson

    When value contains a comma, you should replace any double quotes in the value with two double quotes, before surrounding with double quotes:

    if (value.Contains(“,”))
    {
    value = value.Replace(“\””, “\”\””);
    value = string.Concat(“\””, value, “\””);
    }

  16. STNTZ

    This is a very solid tutorial and guide. Cheers for sharing. Just what I needed in 3 minutes.

Add a Comment