Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

CsvHelper exception Unhandled exception. CsvHelper.HeaderValidationException: Header with name when reading a file generated by CsvWriter

OK I have the following record definition:

    namespace Test09_CSVHelperTest
{
    public sealed record Filter
    {
        public Filter(string body, string category)
        {
            if (string.IsNullOrEmpty(body)) throw new ArgumentException(@"Value cannot be null or empty.", nameof(body));
            if (string.IsNullOrWhiteSpace(body))
                throw new ArgumentException(@"Value cannot be null or whitespace.", nameof(body));
            if (string.IsNullOrEmpty(category))
                category = "Unknown";
            var replaceRegex = new Regex(@"\s+",
                RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace |
                RegexOptions.CultureInvariant);
            Body = replaceRegex.Replace(body, @"\s*");
            Category = category;
        }

        #region Overrides of Object

        public override int GetHashCode()
        {
            return Body.GetHashCode();
        }

        public bool Equals(Filter? other)
        {
            return other is not null && other.Body.Equals(Body, StringComparison.InvariantCultureIgnoreCase);
        }

        #endregion

        //[Name("Body")]
        [Index(0)]
        public string Body { get; }
        [Ignore]
        //[JsonIgnore]
        public string Text => Body.Replace(@"\s*", " ");
        //[Name("Category")]
        [Index(1)]
        public string Category { get; set; }

    }

and I have the following run code:

namespace Test09_CSVHelperTest
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var dirPath = @"d:\Temp01";
            var fileName1 = @"FiltersOutListExport.csv";
            // ReSharper disable once InconsistentNaming
            BindingList<Filter> FiltersOutList = new BindingList<Filter>();
            Directory.CreateDirectory(dirPath);

            for (var i = 0; i < 10; i++)
            {
                var category = $"Category #{i:D2}";
                for (var j = 0; j < 10; j++) FiltersOutList.Add(new Filter($"Filter #{j:D2}", category));
            }

            using (var msTxWriter = new StreamWriter(Path.Combine(dirPath, fileName1) /*ms*/))
            using (var csvWriter = new CsvWriter(msTxWriter, CultureInfo.InvariantCulture))
                csvWriter.WriteRecords(FiltersOutList);

            
            BindingList<Filter> filters;
            
            using (var msReader = new StreamReader(Path.Combine(dirPath, fileName1)))
            using (var csvRead = new CsvReader(msReader,  CultureInfo.InvariantCulture))
            {
              >>  var temp01 = csvRead.GetRecords<Filter>().ToArray();
                filters = new BindingList<Filter>(temp01);
            }

            Console.WriteLine(filters);
            foreach (var filter in filters) Console.WriteLine(filter.Text, "\t", filter.Category);
        }
}

at the line marked with ">>" I get the following Exception:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Unhandled exception. CsvHelper.HeaderValidationException: Header with name 'body'[0] was not found.
Header with name 'category'[0] was not found.
If you are expecting some headers to be missing and want to ignore this validation, set the configuration HeaderValidated to null. You can also change the functionality to do something else, like logging the issue.

IReader state:
   ColumnCount: 0
   CurrentIndex: -1
   HeaderRecord:
["Body","Category"]
IParser state:
   ByteCount: 0
   CharCount: 15
   Row: 1
   RawRow: 1
   Count: 2
   RawRecord:
Body,Category


   at CsvHelper.Configuration.ConfigurationFunctions.HeaderValidated(HeaderValidatedArgs args)
   at CsvHelper.CsvReader.ValidateHeader(Type type)
   at CsvHelper.CsvReader.ValidateHeader[T]()
   at CsvHelper.CsvReader.GetRecords[T]()+MoveNext()
   at System.Collections.Generic.LargeArrayBuilder`1.AddRange(IEnumerable`1 items)
   at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at Test09_CSVHelperTest.Program.Main(String[] args) in G:\My Repos\EGYPHARAOH\2022Projects-Trials\Test09-CSVHelperTest\Program.cs:line 46

Question is: Am I doing something wrong or this is a bug? if it is me then how to do it? if it is a bug is there a work-around?

Things I wish my helpers to take into consideration:

  1. I have googled and did not reach to an answer
  2. I have searched the very stackoverflow.com and none of the available might looks similar gives an answer.
  3. I have used the [Index(0)] and the [Name("PropertyName")] tricks and they did not work, you can find them commented in the record definition code.
  4. The file was written by CsvHelper.CsvWriter itself, no modification or alternation made to the file.

Please, try to help on the noob level kind of answer 🙂
sample of the output file content as is:

Body,Category
Filter\s*#00,Category #00
Filter\s*#01,Category #00
Filter\s*#02,Category #00
Filter\s*#03,Category #00
Filter\s*#04,Category #00
Filter\s*#05,Category #00
Filter\s*#06,Category #00
Filter\s*#07,Category #00
Filter\s*#08,Category #00
Filter\s*#09,Category #00
Filter\s*#00,Category #01
Filter\s*#01,Category #01
Filter\s*#02,Category #01
Filter\s*#03,Category #01
Filter\s*#04,Category #01
Filter\s*#05,Category #01
Filter\s*#06,Category #01
Filter\s*#07,Category #01
Filter\s*#08,Category #01
Filter\s*#09,Category #01
Filter\s*#00,Category #02
Filter\s*#01,Category #02
Filter\s*#02,Category #02
Filter\s*#03,Category #02
Filter\s*#04,Category #02
Filter\s*#05,Category #02
Filter\s*#06,Category #02

>Solution :

The cause of the problem is CsvHelper trying to match the csv record headers (Body, Category) to the Filter constructor parameters in a case-sensitive manner, and there are no Body and Category constructor parameters.

The solution is relatively simple. You can either change the constructor parameter names from

public Filter(string body, string category)

to

public Filter(string Body, string Category)

which is unfortunately not adhering to the common C# style of using camelcase/lowercase for method/constructor parameter names.

Or you can use CsvHelper’s [Name] attribute to define the csv field name for each constructor parameter and keep the camelcase/lowercase constructor parameter names like:

public Filter(
    [Name("Body")] string body,
    [Name("Category")] string category
)
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading