Reputation: 11327
I am using the CsvHelper library to generate a CSV file from an IEnumerable<Person>
, where Person
is a basic class.
public class Person
{
public string DisplayName { get; set; }
public int Age { get; set; }
}
I need to write quoted headers, i.e. instead of "DisplayName", the column in the resulting file should be "Display Name".
How can I do this?
Upvotes: 7
Views: 5289
Reputation: 1
A generic implementation of the top rated answer :
public class TempCSVFile<T, F> where T : class where F : ClassMap
{
public byte[] CreateTempFile(List<T> data)
{
using (var mem = new MemoryStream())
using (var writer = new StreamWriter(mem))
using (var csvWriter = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
csvWriter.Context.RegisterClassMap<F>();
csvWriter.WriteRecords(data);
csvWriter.Flush();
return mem.ToArray();
}
}
}
Also you can use AutoMap if you don't want to change all the properties
public class Person
{
public string DisplayName { get; set; }
public int Age { get; set; }
}
public sealed class PersonMap : ClassMap<Person>
{
public PersonMap()
{
Map(m => m.DisplayName).Name("Display Name");
AutoMap(CultureInfo.InvariantCulture);
}
}
Upvotes: 0
Reputation: 61
Configure the header names with Attributes
Example with Person:
using CsvHelper.Configuration.Attributes;
public class Person
{
[Name("Display Name")]
public string DisplayName { get; set; }
[Name("Age")]
public int Age { get; set; }
}
Another Example:
using CsvHelper.Configuration.Attributes;
public class CompanyExportData
{
[Name("Company Code")]
public string DisplayName { get; set; } = "Store";
[Name("Employee Number")]
public string EmployeeNumber { get; set; }
[Name("Primary Email Address")]
public string PrimaryEmailAddress { get; set; }
}
From the CSVHelper docs on how to use Attributes
Upvotes: 0
Reputation: 23403
Create a ClassMap
.
void Main()
{
using (var stream = new MemoryStream())
using (var writer = new StreamWriter(stream))
using (var reader = new StreamReader(stream))
using (var csv = new CsvWriter(writer))
{
var records = new List<Person>
{
new Test { DisplayName = "one", Age = 1},
new Test { DisplayName = "two", Age = 2 },
};
csv.Configuration.RegisterClassMap<PersonMap>();
csv.WriteRecords(records);
writer.Flush();
stream.Position = 0;
Console.WriteLine(reader.ReadToEnd());
}
}
public class Person
{
public string DisplayName { get; set; }
public int Age { get; set; }
}
public sealed class PersonMap : ClassMap<Person>
{
public PersonMap()
{
Map(m => m.DisplayName).Name("Display Name");
Map(m => m.Age);
}
}
Output:
Display Name,Age
one,1
two,2
Upvotes: 9
Reputation: 2104
I had no headers with workaround, so I did this quick workaround instead:
foreach (var property in typeof(MyCsvClass).GetProperties())
{
csvWriter.WriteField(property.Name.Replace('_', ' '));
}
csvWriter.NextRecord();
csvWriter.WriteRecords(models);
This takes the property names and replace underscore with space, so I could just name the properties with underscores instead of spaces, and it mapped correctly.
It requires, however, that you use the HasHeaderRecord = false
option on the CsvWriter.
Upvotes: 1