I have MultiRecordEngine with a CustomSelector in which I'm trying to loop through many lines starting with different strings
Instead of a long list of 'ifs' like this (which works fine):
if (recordLine.Length == 0)
return null;
if (recordLine.StartsWith("EDI_DC40_U"))
return typeof(IDOC_EDI_DC40_U);
if (recordLine.StartsWith("E2EDL22"))
return typeof(IDOC_E2EDL22);
[...(some more ifs)...]
else
return null;
I wanted to try something more fancy. Having a class with the line prefix in its name for each kind of possible lines, I wanted to do this:
if (recordLine.Length == 0)
return null;
foreach(Type type in GetIDOCTypes()) {
// remove class prefix (IDOC_) from type name
string name = type.Name.Substring(6,type.Name.Length - 5);
if (recordLine.StartsWith(name))
return type;
}
return null
{"You must call BeginRead before use the engine in a foreach loop."} System.Exception {FileHelpers.FileHelpersException}
When I do this I get above Filehelper exception and I just don't get how, when and where I should call the 'BeginRead'...
Is my approach completely wrong?
Here is my sample project.
Thanks!
Have you got a sample project I can look at ? There is certainly nothing to prevent you from doing this specifically unless you are accessing the engines record array but I suspect that you actually returning null rather than a default type thus it doesn't know what type of record you have.
BeginRead must be called in order to start parsing the file in an asynchronous fashion. You haven't actually posted your code to show how you are reading the data. I'm on my phone right now but you must have something like:
var engine = new MultiRecordEngine(typeof (Orders),
typeof (Customer),
typeof (SampleType));
engine.RecordSelector = new RecordTypeSelector(CustomSelector);
var res = engine.ReadFile("Input.txt");
At which point the engine will start to loop through the records in a synchronous pattern calling your custom selector as it goes.
So I took a look at the sample project and it would appear that I failed to make sure to ask you whether you'd checked the inner exceptions. The full error you get from the test project is:
System.Exception was unhandled
HResult=-2146233088
Message=Selector failed to process correctly
Source=FileHelpers
StackTrace:
at FileHelpers.MultiRecordEngine.ReadStream(IRecordReader reader)
at FileHelpers.MultiRecordEngine.ReadFile(String fileName)
at FileHelpersLoopTest.IDOCFileClass.readIDOCFile()
at FileHelpersLoopTest.Program.Main(String[] args)
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
HResult=-2146233086
Message=Index and length must refer to a location within the string.
Parameter name: length
ParamName=length
Source=mscorlib
StackTrace:
at System.String.Substring(Int32 startIndex, Int32 length)
at FileHelpersLoopTest.IDOCFileClass.CustomSelector(MultiRecordEngine engine, String recordLine)
at FileHelpers.MultiRecordEngine.ReadStream(IRecordReader reader)
InnerException:
This should have immediately given you a hint from the inner exception as the stack trace says it failed with "Index and length must refer to a location within the string. Parameter name: length" inside System.String.Substring called from CustomSelector showing that it had indeed reached your code but you were using some incorrect indexing namely the length of the string.
Also, I noticed that you are checking the length of RecordLine but not whether it is null, so another error could occur there. I would advise using System.String.IsNullOrWhiteSpace inside of just checking the length to be safe.
The following works fine for me, but you still have work to do on matching your IODC types to the EDI types that were in the file. I tried to add the EDI_ prefix but the types were still a mismatch so I'll leave that part up to you as I'm assuming this is just down to it being sample data or a naming problem.
// Failing code block
if (string.IsNullOrWhiteSpace(recordLine))
return null;
var types = GetIDOCTypes();
foreach (Type type in types)
{
// remove class prefix (IDOC_) from type name
string name = "EDI_" + type.Name.Substring(6, type.Name.Length - 5);
Console.WriteLine($"{name} vs {recordLine.Substring(0, name.Length)}");
if (recordLine.StartsWith(name))
return type;
}
return null;
// END Failing code block