FileHelpers DelimitedClassBuilder add fields after read

504 views Asked by At

I'm using the FileHelpers DelimitedClassBuilder to build a class based on metadata in a datatable. This way I can read any file known in the metadata. I read it as a stream and process each record individually. For further processing I want to add some fields to the data and then serialize it to JSON. It's the adding of fields part that doesn't work. The stream returns an object. I'm using a work-around. Serializing the object to JSON, de-serializing it to a dictionary, adding the fields and then serializing it to JSON again. I'm sure this can be done in a more efficient way. I tried converting it to a list but that doesn't work.

//build runtime class based on metadata
FD.DelimitedClassBuilder cb = new FD.DelimitedClassBuilder("ImportFile", "|");
cb.IgnoreFirstLines = 1;
foreach (DT.DataRow drMetadata in dtMetadata.Rows)
{
    cb.AddField(drMetadata["EntityColumnName"].ToString(), typeof(string));
    cb.LastField.FieldQuoted = true;
    cb.LastField.QuoteMode = FH.QuoteMode.AlwaysQuoted;
    cb.LastField.QuoteMultiline = FH.MultilineMode.AllowForBoth;
}
//create async filehelper engine for row by row processing
FH.FileHelperAsyncEngine fhe = new FH.FileHelperAsyncEngine(cb.CreateRecordClass());

using (fhe.BeginReadStream(file))
{
    foreach(object record in fhe)
    {
        //convert object to list, doesn't work
        //SG.List<object> blaat = (record as SG.IEnumerable<object>).Cast<object>().ToList();

        //serialize record class to json
        string json = JS.JsonConvert.SerializeObject(record, JS.Formatting.Indented);
        //convert message to key-value dictionary
        SG.IDictionary<string, string> values = JS.JsonConvert.DeserializeObject<SG.IDictionary<string, string>>(json);

        values.Add("SourceSystem", messagesource);
        values.Add("SourceType", messagetype);

        string json2 = JS.JsonConvert.SerializeObject(values, JS.Formatting.Indented);

        SY.Console.WriteLine(json2);
    }
}
fhe.Close();
1

There are 1 answers

0
shamp00 On

You can use a list of fields obtained via reflection on the record class. Then use Linq's ToDictionary to populate your values.

var recordClass = cb.CreateRecordClass();
List<FieldInfo> fields = recordClass.GetFields().ToList();

FileHelperAsyncEngine fhe = new FileHelperAsyncEngine(recordClass);
using (fhe.BeginReadStream(file))
{
    foreach (var record in fhe)
    {
        IDictionary<string, object> values = fields.ToDictionary(x => x.Name, x => x.GetValue(record));

        values.Add("SourceSystem", "messagesource");
        values.Add("SourceType", "messagetype");

        string json = JsonConvert.SerializeObject(values, Formatting.Indented);

        Console.WriteLine(json);
    }
}