The following C# code used to work with csvReader
where variable reader is a StreamReader
:
DataTable dataTable = null;
this._csvHeaders = null;
using (reader)
{
using (CsvReader csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
csv.Configuration.HasHeaderRecord = true;
csv.Configuration.MissingFieldFound = (field, index, context) => AddMissingFieldParseError(field, context.Row, index);
csv.Configuration.BadDataFound = (context) => AddBadDataFoundParseError(context.Field, context.Row);
using (CsvDataReader dataReader = new CsvDataReader(csv))
{
// Validate headers
this._csvHeaders = csv.Context.Reader.HeaderRecord.ToList();
TrimHeaderNames(ref _csvHeaders);
string errorMessage = string.Empty;
if (!ValidateHeaders(_csvHeaders, out errorMessage))
{
XOperationError operationError = new XOperationError("Duplicated error found", errorMessage);
this.ParseErrors.Clear();
this.ParseErrors.Add(0, new List<XOperationError> { operationError });
return null;
}
dataTable = new DataTable();
dataTable.Load(dataReader);
}
}
}
Now it no longer works as HasHeaderRecord
, MissingFieldFound
, BadDataFound
all became read-only.
I tried to remove the 3 lines and added the following before the new CsvReader()
statement:
CsvConfiguration config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
HasHeaderRecord = true,
MissingFieldFound = (field, index, context) => AddMissingFieldParseError(field, context.Row, index),
BadDataFound = (context) => AddBadDataFoundParseError(context.Field, context.Row)
};
Now it complains:
MissingFieldFound
does not take 3 argumentsBadDataFoundArgs
does not contain a definition for row
I'm really confused. Are these just syntax errors?
Any help is appreciated.
The following C# code used to work with csvReader
where variable reader is a StreamReader
:
DataTable dataTable = null;
this._csvHeaders = null;
using (reader)
{
using (CsvReader csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
csv.Configuration.HasHeaderRecord = true;
csv.Configuration.MissingFieldFound = (field, index, context) => AddMissingFieldParseError(field, context.Row, index);
csv.Configuration.BadDataFound = (context) => AddBadDataFoundParseError(context.Field, context.Row);
using (CsvDataReader dataReader = new CsvDataReader(csv))
{
// Validate headers
this._csvHeaders = csv.Context.Reader.HeaderRecord.ToList();
TrimHeaderNames(ref _csvHeaders);
string errorMessage = string.Empty;
if (!ValidateHeaders(_csvHeaders, out errorMessage))
{
XOperationError operationError = new XOperationError("Duplicated error found", errorMessage);
this.ParseErrors.Clear();
this.ParseErrors.Add(0, new List<XOperationError> { operationError });
return null;
}
dataTable = new DataTable();
dataTable.Load(dataReader);
}
}
}
Now it no longer works as HasHeaderRecord
, MissingFieldFound
, BadDataFound
all became read-only.
I tried to remove the 3 lines and added the following before the new CsvReader()
statement:
CsvConfiguration config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
HasHeaderRecord = true,
MissingFieldFound = (field, index, context) => AddMissingFieldParseError(field, context.Row, index),
BadDataFound = (context) => AddBadDataFoundParseError(context.Field, context.Row)
};
Now it complains:
MissingFieldFound
does not take 3 argumentsBadDataFoundArgs
does not contain a definition for row
I'm really confused. Are these just syntax errors?
Any help is appreciated.
Share Improve this question edited Mar 21 at 5:39 marc_s 756k184 gold badges1.4k silver badges1.5k bronze badges asked Mar 20 at 23:49 T. J. FanT. J. Fan 777 bronze badges 1- github/JoshClose/CsvHelper/blob/… – Hans Passant Commented Mar 20 at 23:57
2 Answers
Reset to default 1The call to csv.Configuration
actually returns an IReaderConfiguration
which is an interface implemented by the underlying CsvConfiguration
class. As far as I can tell this was changed in 20.0.0 to avoid threading issues.
The idea is that the Configuration is immutable once it's been passed to the reader. So if you want to change it, you have to inject it (as you've mentioned):
using (reader){
var configuration = new CsvConfiguration(CultureInfo.InvariantCulture);
// Note the culture is now in the configuration
// Set up the rest of your configuration here
using (CsvReader csv = new CsvReader(reader, configuration)) {
// etc.
MissingFieldFound
now takes 1 argument, MissingFieldFoundArgs
. BadFoundData
takes BadDataFoundArgs
. It looks like that last one now has a Field
, RawRecord
and Context
. I think Context.Reader
might have the info you're looking for with respect to the row, if the context doesn't. Try this:
MissingFieldFound = (args) => AddMissingFieldParseError(args), // MissingFieldFoundArgs
BadDataFound = (args) => AddBadDataFoundParseError(args) // BadDataFoundArgs
Debug those args and you will be able to see what information you can retrieve from them. But setting them up before the using
call is the right thing to do.
(You can see the list of changes in the changelog in case you run into further issues.)
I was able to figure out the parameters finally. Here are the solutions:
CsvConfiguration config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
HasHeaderRecord = true,
MissingFieldFound = (args) => AddMissingFieldParseError(args.Context.Reader.HeaderRecord, args.Context.Reader.Parser.Row, args.Index),
BadDataFound = (args) => AddBadDataFoundParseError(args.Field, args.Context.Reader.Parser.Row)
};