37

I am using the class CsvReader successfully and am happy with it, however, the file that I consume is being produced by a group which changes column formats without letting me know.

So, one moment everything is working, then the next morning things break and the try catch block around csv.GetRecord<MyType>() catches the error and logs the error, however I can't gather any valuable info from the Exception instance. It just says: "The conversion cannot be performed." and the InnerException has nothing. Not very useful. I don't even know which one of my 150 columns are causing the problem.

Can you help me figure out how I can pinpoint which column in which row is causing the problem?

Thanks

Shiva
  • 20,575
  • 14
  • 82
  • 112
t316
  • 1,149
  • 1
  • 15
  • 28

3 Answers3

51

Currently, there is no way to ignore errors at the field/property level. Your current options are these:

Look at the exception data.

catch( Exception ex )
{
    // This contains useful information about the error.
    ex.Data["CsvHelper"];
}

Ignore reading exceptions. This is on a row level, though, not field. It will allow the whole file to still be read, and just ignore the rows that don't work. You can get a callback when an exception occurs.

csv.Configuration.IgnoreReadingExceptions = true;
csv.Configuration.ReadingExceptionCallback = ( ex, row ) =>
{
    // Do something with the exception and row data.
    // You can look at the exception data here too.
};
Shahin
  • 12,543
  • 39
  • 127
  • 205
Josh Close
  • 22,935
  • 13
  • 92
  • 140
12

First of all, it seems that I need to catch CsvTypeConverterException.

 while (csv.Read())
    {
       try
       {    
          var record = csv.GetRecord<MyType>();    
       }
       catch (CsvTypeConverterException ex)
       {
         //ex.Data.Values has more info...
       }
    }

I now know how to investigate what went wrong, but how do I make sure that that field is skipped but the rest of the fields in that row are converted, so that not the entire row is thrown away?

Thanks

t316
  • 1,149
  • 1
  • 15
  • 28
  • 1
    You've probably figured it out already, but to answer your question on how to skip a record, check the configuration "ShouldSkipRecord", you can set a callback function to be called in such cases. – firepol Feb 10 '16 at 15:33
  • It seems that putting a try/catch in a while loop like this DRAMATICALLY slows down the whole process. I've noticed this while looping over a .csv with ~500k lines – Omar Himada Mar 13 '20 at 21:59
1

CsvHelper has public 'Context' field in the CsvReader and there are all what needed for display a problem:

try
{
    var records = csvReader.GetRecords<MyType>().ToList();
}
catch (CsvHelperException e)
{
    Console.WriteLine($"{e.Message} " + (e.InnerException == null ? string.Empty : e.InnerException.Message));
    Console.WriteLine($"Row: {csvReader.Context.Row}; RawLine: {csvReader.Context.RawRecord}");
    if (csvReader.Context.CurrentIndex >= 0 &&
        csvReader.Context.CurrentIndex < csvReader.Context.HeaderRecord.Length)
    {
        Console.WriteLine($"Column: {csvReader.Context.CurrentIndex}; ColumnName: {csvReader.Context.HeaderRecord[csvReader.Context.CurrentIndex]}");
    }
    throw;
}
Pavel K.
  • 983
  • 9
  • 21