Search code examples
c#.net-corecsvhelper

CsvHelper ByteArrayConverter NullValues problem


I'm having a bit of a problem with converting an empty (value is "NULL") Key field to a byte array with CsvHelper, i keep getting this exception:

CsvHelper.ReaderException: An unexpected error occurred.
---> System.FormatException: Could not find any recognizable digits.
at System.ParseNumbers.StringToInt(ReadOnlySpan`1 s, Int32 radix, Int32 flags, Int32& currPos)
at System.Convert.ToByte(String value, Int32 fromBase)
at CsvHelper.TypeConversion.ByteArrayConverter.HexStringToByteArray(String hex)
at CsvHelper.TypeConversion.ByteArrayConverter.ConvertFromString(String text, IReaderRow row, MemberMapData memberMapData)
at lambda_method(Closure )
at CsvHelper.Expressions.RecordCreator.Create[T]()
at CsvHelper.Expressions.RecordManager.Create[T]()
at CsvHelper.CsvReader.GetRecord[T]()
--- End of inner exception stack trace ---

The mapping is set up like this:

public sealed class ZaznamMapping : ClassMap<Zaznam>
{
    public ZaznamMapping(FileSettings configuration)
    {
        var nullValues = new[] { "NULL", "null", string.Empty };

        for (int i = 0; i < configuration.Count(); i++)
        {
            switch (configuration[i])
            {
                case Col.Ignore: continue;
                case Col.Id:     Map(m => m.Id).Index(i).TypeConverterOption.NullValues(nullValues); break;
                case Col.Idd:    Map(m => m.Idd).Index(i).TypeConverterOption.NullValues(nullValues); break;
                case Col.Data:   Map(m => m.Data).Index(i).TypeConverterOption.NullValues(nullValues); break;
                case Col.Key:    Map(m => m.Key).Index(i).TypeConverterOption.NullValues(nullValues); break;
                default: throw new NotSupportedException($"Mapping() - Unknown column \"{configuration[i].ToString()}\"!");
            }
        }
    }
}

And Zaznam class:

public sealed class Zaznam
{
    public int Id { get; set; }
    public int Idd { get; set; }
    public byte[] Data { get; set; }
    public byte[] Key { get; set; }
}

The value in file Key coluimn is literally NULL (as in string containing the letters "NULL"). Should not the ByteArrayconverter respect the TypeConverterOptions?

The questions being:

  • Am I doing something wrong?
  • Should I be making my own converter instead?

Solution

  • It looks like the null value logic wasn't added to ByteArrayConverter. If you look at StringConverter, the same null logic is not in the ConvertFromString method for ByteArrayConverter. You should be able to create your own custom TypeConverter to add the logic and then register it for all byte[].

    public class NullByteArrayConverter : ByteArrayConverter
    {
        public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
        {
            foreach (var nullValue in memberMapData.TypeConverterOptions.NullValues)
            {
                if (text == nullValue)
                {
                    return null;
                }
            }
    
            return base.ConvertFromString(text, row, memberMapData);
        }
    }
    
    csv.Configuration.TypeConverterCache.AddConverter<byte[]>(new NullByteArrayConverter());