How do I fix a ConvertException while importing a csv file with the filehelpers library
I am processing a csv file that occasionally has text in an int field due to user input error. It is the first column and basically it is supposed to be a unique record id. I am catching the errors using engine.ErrorManager.ErrorMode = ErrorMode.SaveAndContinue;
What I would rather do is just have the error ignored and replace the text with a numeric value of my choosing and still have that row included with the processed results.
I would even be fine with the process just sticking in the default value that I have declared in the file definition class file: [FieldNullValue(typeof(int), "0")]
One other thing is I am determining what file to parse at runtime like so:
Type t = assembly.GetType(assemblyName.Name + ".FileDefinitions." + className);
FileHelperEngine engine = new FileHelperEngine(t);
So I am not sure how to implement D.Lambert's suggestion in the context of what to put in for <CustomersFixedWithNumericId>
So to clarify there are 7 different file definitions (class files) that get uploaded/processed, but all of them hav开发者_如何学运维e the CustomerId field.
Given the current state of FileHelpers, you really have to define that field as a string and try to do your own validation on it.
I looked at a couple different ways of addressing this -- first, I tried setting up a record using a property rather than a field. This could conceivably have allowed you to create a String property and validate inputs on the Set. This turned out to be difficult because:
- Attributes are set to target fields only (fairly easy fix if you want to modify FileHelpers code.
- Private fields for properties have to be marked w/ [FieldNotInFile] attribute (annoyance).
- Properties aren't handled in RecordInfo.CreateCoreFields() method. This one is a little more involved to fix, since you really would have to create a merged list of properties and fields in the correct order. This is the point where I stopped looking into this method.
Next plan: use the record definition as-is, and validate during the read. Set up an event handler on the engine:
engine.AfterReadRecord += new Events.AfterReadHandler<CustomersFixedWithNumericId>(engine_AfterReadRecord);
var res = engine.ReadFile(path);
Then handle bad values in the handler:
void engine_AfterReadRecord(EngineBase engine, Events.AfterReadEventArgs<CustomersFixedWithNumericId> e)
{
int intVal;
int.TryParse(e.Record.CustomerID, out intVal);
e.Record.CustomerID = intVal.ToString();
}
Neither of these are perfect, but I think the second is reasonably close.
Addendum: This shows the technique above with a late-bound class:
public void TestMethod1()
{
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
Type t = assembly.GetType("FileHelpers.Tests.CustomersFixedWithNumericId");
FileHelperEngine engine = new FileHelperEngine(t);
string path = @"pathtofile\BadCustomersFixedNumericId.txt";
engine.AfterReadRecord += new Events.AfterReadHandler<object>(engine_AfterReadRecord);
var res = engine.ReadFile(path);
}
void engine_AfterReadRecord(EngineBase engine, Events.AfterReadEventArgs<object> e)
{
// validation here
}
精彩评论