Search code examples
c#csvexport-to-csvcsvhelper

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();
        }

Solution

  • 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();
    }