Rob J
Rob J

Reputation: 33

Generate CSV with dynamic headers using CsvHelper

I have a records in my DB which i would like to generate CSV, I am using CsvHelper library for that. The data structure of the records which needs to generated as a csv is given below. enter image description here Observer "additional_details" column, it contains a JSON object. A new column should be added in the csv output for each unique JSON key. See the image below enter image description here

This is what I am trying to do at the moment:-

 My c# model

    public class Data 
    { 
        public bool ConfirmedAttendance {get; set;}
        public bool DigitalDelivery {get; set;}
        public string ProfileCode {get; set;}
        public ExpandoObject AdditionalDetails { get; set; }
    }

    So, I will be getting a `IList<Data> _data;` 


                using var stream = new MemoryStream();
                using var writer = new StreamWriter(stream);
                using var csvWriter = new CsvWriter(writer, System.Globalization.CultureInfo.CurrentCulture);
                csvWriter.Configuration.HasHeaderRecord = true;
                csvWriter.WriteHeader<Data>();
    
                   //A dictionary to hold each column and its value.
                    var _addintionalDetails = new Dictionary<string, string>();
                    
                  //populating the above dictionary with the unique json key.
                    foreach (var record in _data)
                    {
                        foreach (var item in (IDictionary<String, Object>)record.AdditionalDetails)
                        {
                            if(!_addintionalDetails.ContainsKey(item.Key))
                            {
                                _addintionalDetails.Add(item.Key, item.Value.ToString());
                            }
                        }
                    }

                  //Adding new column in the csv output from the above dictionary. 
                    foreach (var header in _addintionalDetails)
                    {
                        csvWriter.WriteField(header.Key.Humanize(LetterCasing.AllCaps));
                    }
                   
                    await csvWriter.NextRecordAsync();
    
                    //Adding records to my csv
                    foreach (var row in input.Records)
                    {
                       //How to add records for additional details ??
                        await AddRecordAsync(csvWriter, row);
                       
                    }
                    writer.Flush();
                    stream.Seek(0, SeekOrigin.Begin);
                    input.Stream = stream.ToArray();



        private static async Task AddRecordAsync(CsvWriter csvWriter, Data row)
        {
            csvWriter.WriteRecord<Data>(row);
           
            await csvWriter.NextRecordAsync();
        }

Upvotes: 3

Views: 2338

Answers (1)

David Specht
David Specht

Reputation: 9094

Here is an updated version of AddRecordAsync. You would also need to pass the _addintionalDetails to it.

private static async Task AddRecordAsync(CsvWriter csvWriter, Data row, Dictionary<string, string> _addintionalDetails)
{
    csvWriter.WriteRecord(row);

    var additional = row.AdditionalDetails as IDictionary<string, object>;

    foreach (var header in _addintionalDetails)
    {
        if (additional.ContainsKey(header.Key))
        {
            csvWriter.WriteField(additional[header.Key]);
        }
        else
        {
            csvWriter.WriteField(string.Empty);
        }
    }

    await csvWriter.NextRecordAsync();
}

Upvotes: 2

Related Questions