Search code examples
c#csvcsvhelper

How do I replace missing fields in .csv file with default value when the missing field is the last one in the index?


I am trying to use CsvHelper to read a csv file with a few optional properties. Whenever I read the csv, I end up with the error message: CsvHelper.MissingFieldException: Field at index '6' does not exist. You can ignore missing fields by setting MissingFieldFound to null. Below is my simple Program and the TagModel I am comparing:

// Using Directive
using System;
using System.Globalization;
using ProjectName;
using CsvHelper;
using CsvHelper.Configuration;

internal class Program
{
    public static void Main(string[] args)
    {
        //Determine filepath for the input.csv file
        string inputFile = @"C:\Users\kaden.hansen\Desktop\Huntsman\CPBC14.csv";

        //Initialize CSVHelper NuGet package tools
        using (var reader = new StreamReader(inputFile)) //Set reader to read the inputFile
        using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
        {
           csv.Context.Configuration.MissingFieldFound = null;
            var tags = csv.GetRecords<TagModel>(); //Retrieve records to "tags" IEnumarable
            try
            {
                foreach (var tag in tags)
                {
                    
                    Console.WriteLine(tag.TagName);
                    
                }
            } catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

        Console.WriteLine("Finished reading CSV!");
    }
}

And the Tag Model:

// Using Directive
using CsvHelper.Configuration.Attributes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ProjectName
{
    public class TagModel
    {
        // Determine Properties (or "columns") returned by the CSV File.

        [Name("Hierarchical Name")] //This is the name of the property as it appears in the CSV file row 1.
        [Default("")] //This sets a default value for when the field returns as empty.
        public string? HierarchicalName { get; set; } // This determines the declaration name that the script will use to access the property, including its type.

        [Name("Strategyname")]
        [Default("")]
        public string? StrategyName { get; set; }

        [Name("Tagname")]
        [Default("")]
        public string? TagName { get; set; }

        [Name("Type")]
        [Default("")]
        public string? Type { get; set; }

        [Name("Attribute")]
        [Default("")]
        public string? Attribute { get; set; }

        [Name("Value")]
        [Default("")]
        public string? Value { get; set; }

        [Name("IA Reference")]
        [Default("")]
        [Optional]
        public string? IAReference { get; set; }
    }
}

I have included the suggestion listed in the error message: csv.Context.Configuration.MissingFieldFound = null;. I also made sure to make the properties nullable with the string? in the TagModel class. I included [Optional] on the property that tends to throw the error. With all of these, the same error shows in my catch statement. When I removed the "IAReference" property, it read each TagName up to the first row in the csv that was missing the "Value" Property. I concluded that it handles missing properties just fine as long as it isn't the final property in the index.

I am fairly new to C# so it could be some syntax issue, but any help is greatly appreciated!


Solution

  • Starting with version 20.0, the MissingFieldFound must be set on the CsvConfiguration and then passed into the CsvReader constructor.

    Changed CsvConfiguration to a read only record to eliminate threading issues.

    It isn't necessary to make the properties nullable string? and [optional] just means it is optional to include the property in the CSV header. Your issue is the IAReference has been included in the header, but if there is no data for it, the last comma is missing.

    Incorrect CSV

    Attribute,Value,IA Reference
    My Attribute,My Value
    

    Correct CSV

    Attribute,Value,IA Reference
    My Attribute,My Value,
    

    Solution

    var config = new CsvConfiguration(CultureInfo.InvariantCulture)
    {
        MissingFieldFound = null
    };
    
    using (var reader = new StreamReader(inputFile)) 
    using (var csv = new CsvReader(reader, config))