CsvHelper
CsvHelper copied to clipboard
InvalidOperationException while reading to a positional record with custom convert
Describe the bug
When I try to read document, that has a Convert
in it's class map to a positional record, CsvHelper fails with a exception
To Reproduce
I have a csv document, that contains unprocessed data in a cell (a list, separated by unique separator).
Id,Entries
Some,Entry1|Entry2
The corresponding entity could be defined
public record Foo(
string Id,
IEnumerable<string> Entries);
With class map
public sealed class FooMap : ClassMap<Foo>
{
public FooMap()
{
AutoMap(CultureInfo.InvariantCulture); // Also I tried without AutoMap
Map(x => x.Entries).Convert(args => args.Row
.GetField<string>(nameof(Foo.Entries))?
.Split('|')
.Select(entry=> entry.Trim())
.Where(entry => !string.IsNullOrEmpty(entry)) ?? Enumerable.Empty<string>());
}
}
Then I do the simple call:
using var reader = new StreamReader(stream);
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
csv.Context.RegisterClassMap<FooMap>();
return csv.GetRecords<Foo>();
Expected behavior
No exception should appear, explicit Convert
construction should be used
Additional context Here is the stacktrace from my business app
CsvHelper.ReaderException: An unexpected error occurred.
IReader state:
ColumnCount: 0
CurrentIndex: 1
HeaderRecord:
["EmployeeId","Roles","CostCenterCode","OrgLevelId"]
IParser state:
ByteCount: 0
CharCount: 141
Row: 2
RawRow: 2
Count: 4
RawRecord:
SomeId,Role1|Role2|Role3|Role4,SomeCostCenterCode,SomeOrgLevelId
---> System.InvalidOperationException: Member is not a property or a field.
at CsvHelper.TypeConversion.IEnumerableGenericConverter.ConvertFromString(String text, IReaderRow row, MemberMapData memberMapData)
at lambda_method28(Closure )
at CsvHelper.Expressions.RecordCreator.Create[T]()
at CsvHelper.Expressions.RecordManager.Create[T]()
at CsvHelper.CsvReader.GetRecords[T]()+MoveNext()
--- End of inner exception stack trace ---
at CsvHelper.CsvReader.GetRecords[T]()+MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at NameSpace.HandlerName(Request request, CancellationToken cancellationToken) in ...
Also I need to add that everything will work if I will define my record as standard one
public record Foo
{
public string Id { get; init; } = default!;
public IEnumerable<string> Entries { get; init; } = new List<string>();
}