Search code examples
c#csvhelper

CSV file Blank field error with CSVHelper C#


I've a problem to read this file with CSVHelper for example, how can I use a ShouldSkipRecord to not receive a exception? I've tried to keep all my Map columns Optional but doesn't work.

PrintScreen Data

Class:

public class WheelProsAccessoriesInventoryItem : WheelProsBaseInventoryItem
   {
       public override string PartNumber { get; set; }
       public override string PartDescription { get; set; } 
       public override string Brand { get; set; } 
       public string CapHardwareDescription { get; set; } 
       public string CapScrewQuantity { get; set; } 
       public string CapWrench { get; set; } 
       public string CapStyleDescription { get; set; } 
       public string ImageURL { get; set; } 
       public override string TotalQOH { get; set; } 
       public override string Msrp { get; set; } 
       public override string Map { get; set; } 
       public override string RunDate { get; set; } 
       public override string StockLa1 { get; set; } 
       public override string num1015 { get; set; } 
       public override string num1019 { get; set; } 
       public override string num1022 { get; set; } 
       public override string num1028 { get; set; } 
       public override string StockLa2 { get; set; } 
       public override string num1036 { get; set; } 
       public override string num1071 { get; set; } 
       public override string num1072 { get; set; } 
       public override string num1082 { get; set; }  
       public override string StockLa3 { get; set; } 
       public override string StockTX { get; set; } 
       public override string num1092 { get; set; } 
       public override string StockLangley { get; set; } 
       public override string StockToronto { get; set; } 
       public int LineNumber { get; set; }
   }

}

MAP:

public class WheelProsAccessoriesInventoryItemMap : ClassMap<WheelProsAccessoriesInventoryItem>
    {**

        public WheelProsAccessoriesInventoryItemMap()
        {
            Map(m => m.PartNumber).Name("PartNumber");
            Map(m => m.Brand).Name("Brand");
            Map(m => m.PartDescription).Name("PartDescription");


            Map(m => m.CapHardwareDescription).Name("CapHardwareDescription").Optional();
            Map(m => m.CapScrewQuantity).Name("CapScrewQuantity").Optional();
            Map(m => m.CapWrench).Name("CapWrench").Optional();
            Map(m => m.CapStyleDescription).Name("CapStyleDescription").Optional();

            Map(m => m.ImageURL).Name("ImageURL");
  
            Map(m => m.TotalQOH).Name("TotalQOH");
            Map(m => m.Msrp).Name("MSRP");
            Map(m => m.Map).Name("MAP");
            Map(m => m.RunDate).Name("RunDate"); 

            // StockWarehouses

            // 1011 – Stock LA1 Warehouse
            Map(m => m.StockLa1).Name("1011");

            // 1031 - Stock LA2 Riverside
            Map(m => m.StockLa2).Name("1031");

            // 1085 – Stock LA3 LA Warehouse Support
            Map(m => m.StockLa3).Name("1085");

            // 1086 - StockTX Dallas Warehouse
            Map(m => m.StockTX).Name("1086");

            // 4033 - Stock Langley/Vancouver
            Map(m => m.StockLangley).Name("4033");

            // 4035 - Stock Toronto
            Map(m => m.StockToronto).Name("4035");

            // 1088 - Stock US - Atlanta Logistics Center
            Map(m => m.num1088).Name("1088"); 

            Map(m => m.num1015).Name("1015").Optional();
            Map(m => m.num1019).Name("1019").Optional();
            Map(m => m.num1022).Name("1022").Optional();
            Map(m => m.num1028).Name("1028").Optional();
            Map(m => m.num1036).Name("1036").Optional();
            Map(m => m.num1071).Name("1071").Optional();
            Map(m => m.num1072).Name("1072").Optional();

            // Map(m => m.LineNumber).Convert(record => record.Row.Parser.Row);

        }

    }
}

Read Method:

 public static IEnumerable<T> GetRecords<T, TMap>(string filename, bool hasFrenchChars = false)
    where T : class
    where TMap : ClassMap<T>
    {
        var errorRecsCollection = new List<string>();
        var malformedRow = false;

       

            using (var streamReader = new StreamReader(filename))
            {
                using (var csvReader = new CsvReader(streamReader, CultureInfo.InvariantCulture))
                {

                    csvReader.Context.RegisterClassMap<TMap>();


                    var config = new CsvConfiguration(CultureInfo.InvariantCulture)
                    {
                        Delimiter = ",",
                        HasHeaderRecord = true,
                        Encoding = hasFrenchChars ? Encoding.GetEncoding("ISO-8859-1") : Encoding.UTF8,
                        IgnoreBlankLines = true,
              
                        MissingFieldFound = null,
                        
                        BadDataFound = context =>
                        {
                            malformedRow = true;

                            errorRecsCollection.Add(context.RawRecord);

                        }

                    };

                  //  var rowNumber = csvReader.Parser.Row;
                return csvReader.GetRecords<T>().ToList();


                }

            }
       
         
    }

How I need to do to ignore the files? I've tried to add this config below but doesn't works.


Solution

  • This is how I handle bad records (all code in the same method)

    var isRecordBad = false;
    csv.Configuration.BadDataFound = context =>
    {
        isRecordBad = true;
        bad.Add(context.RawRecord);
    };
    
    var records = csv.GetRecords<dynamic>(); //You can still use your type and map, dynamic is sometimes just easier for complicated mappings
    
    foreach (var record in records)
    {
        var dictionary = record as IDictionary<string, object>;
        if (!isRecordBad)
        {
            //keep the data - add to list
        }
        isRecordBad = false;
    }
    

    If you decide to go the dynamic type route you can also write less code and just check for the keys in the converted dictionary when generating the WheelProsAccessoriesInventoryItem object