4

I am using CsvHelper to convert dapper objects to CsvFiles. I am using classmaps to map properties for indices and name mapping. The issue is I need a row with the table title before the records are written as mentioned below:

enter image description here

My old code without the title:

  using (var writer = new StreamWriter(@"C:\Users\NPandian\Desktop\test.csv", false, System.Text.Encoding.UTF8))

        using (var csvWriter = new CsvWriter(writer))
        {
            var ReportName = "Test Class";
            csvWriter.Configuration.RegisterClassMap(classMap);
            csvWriter.WriteRecords(records);
            writer.Close();
        }

Old Csv:

enter image description here

My Current work around code:

            using (var writer = new StringWriter())
            using (var csvWriter = new CsvWriter(writer))
            {
                var ReportName = "Test Class";
                csvWriter.Configuration.RegisterClassMap(classMap);
                csvWriter.WriteRecords(records);
                writer.Close();
                return $"ReportName:, {ReportName},\n{csvWriter.Context.Writer.ToString()}";
            }

My Questions: 1) Is it possible with CsvHelper? 2) If so How?

8
  • Possible duplicate of Writing a Header using CsvHelper? C# Commented May 21, 2019 at 12:45
  • Its not.... I am able to write the headers and the records. I need to write one record above it with a separate record that has the title of the table I am writing. If I am configuring with the class map. Any manual addition to it wipes the csv full clean. Nothing comes out of it. Commented May 21, 2019 at 12:48
  • 1
    If you add a title you no longer have a CSV. And the developers that try to read that file won't be very happy. In any case, since the title isn't related to CSV data you can just write directly to the StreamWriter, eg use writer.WriteLine("Title : {0}",someText); before the call to csvWriter.WriteRecords Commented May 21, 2019 at 12:50
  • Anything thats not csv data related, can't be mapped using csv helper. Its supposed to be for humans btw, why we need the title to let the humans know what they are reading. If someone can confirm this is definitly not a planned possibility with csvhelper I can stick with the workaround code. Commented May 21, 2019 at 12:53
  • @NarendranPandian the code needs fixing. You don't need a StringWriter in the first place since you already have a StreamWriter Commented May 21, 2019 at 12:54

3 Answers 3

8

You can write fields and rows by hand.

void Main()
{
    var records = new List<Foo>
    {
        new Foo { Id = 1, Name = "one" },
        new Foo { Id = 2, Name = "two" },
    };
    using (var writer = new StringWriter())
    using (var csv = new CsvWriter(writer))
    {
        csv.Configuration.RegisterClassMap<FooMap>();

        csv.WriteField("Title:");
        csv.WriteField("Title");
        csv.NextRecord();

        csv.WriteRecords(records);
        writer.ToString().Dump();
    }
}

public class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class FooMap : ClassMap<Foo>
{
    public FooMap()
    {
        Map(m => m.Id).Index(0).Name("S.No.");
        Map(m => m.Name).Index(1);
    }
}

Output:

Title:,Title
S.No.,Name
1,one
2,two
Sign up to request clarification or add additional context in comments.

Comments

2

CSV files have no titles. The question describes a flat text report, not a CSV file. CsvHelper, as the name implies, is a helper library that writes CSVs, it's not a full featured report generator.

The library allows other code to write arbitrary text before or after it finished though, as it works on top of an abstract TextWriter instead of a stream or file. One could even write extra text between records if required.

You can use the writer you already have to write whatever you want before or after the call to csvWriter.WriteRecords(records);, eg :

using (var writer = new StreamWriter(@"C:\Users\NPandian\Desktop\test.csv", false, System.Text.Encoding.UTF8))
using (var csvWriter = new CsvWriter(writer))
{
    var ReportName = "Test Class";
    csvWriter.Configuration.RegisterClassMap(classMap);

    //Doesn't matter where this is called as long as it is before `WriteRecords`
    writer.WriteLine($"ReportName:, {ReportName}");

    csvWriter.WriteRecords(records);

    //No need to explicitly close, that's what `using` is for
}

CsvWriter accepts any TextWriter object and just writes its data to that writer. It doesn't try to modify it in any other way. It won't affect any other text already written to that TextWriter

Comments

1

For CSVHelper version 15.0.0 and above use:

void Main()
{
    var records = new List<Foo>
    {
        new Foo { Id = 1, Name = "one" },
        new Foo { Id = 2, Name = "two" },
    };
    using (var writer = new StringWriter())
    using (var csv = new CsvWriter(writer, CultureInfo.CurrentCulture))
    {
        csv.Configuration.RegisterClassMap<FooMap>();

        csv.WriteField("Title:");
        csv.WriteField("Title");
        csv.NextRecord();

        csv.WriteRecords(records);
        writer.ToString().Dump();
    }
}

public class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class FooMap : ClassMap<Foo>
{
    public FooMap()
    {
        Map(m => m.Id).Index(0).Name("S.No.");
        Map(m => m.Name).Index(1);
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.