public override async Task WriteStreamAsync(TextWriter writer, IEnumerable <ExpandoObject> records, bool flush = true)
        {
            writer.NewLine = Environment.NewLine;
            var lineNumber = 1;

            foreach (ExpandoObject expandoObject in records)
            {
                BeforeFluentWriteEventArgs beforeWriteArgs = OnBeforeWriteRecord(expandoObject, lineNumber);

                var record = (beforeWriteArgs.LineChanged ? beforeWriteArgs.Record : expandoObject) as IDictionary <string, object>;

                if (record == null || beforeWriteArgs.SkipRecord)
                {
                    lineNumber++;
                    continue;
                }
                if (!record.ContainsKey(recordTypeProperty))
                {
                    throw new BadFluentConfigurationException($"The record must contais a property called '{recordTypeProperty}'");
                }

                MultiRecordItem recordItem = GetLineDescriptor((string)record[recordTypeProperty]);
                var             sb         = new StringBuilder();

                foreach (KeyValuePair <string, object> keyValuePair in record)
                {
                    if (!recordItem.Descriptor.Fields.TryGetValue(keyValuePair.Key, out IFieldInfoTypeDescriptor fieldDescriptor))
                    {
                        throw new Exception($"The field {keyValuePair.Key} is not configured");
                    }

                    if (fieldDescriptor.IsArray)
                    {
                        sb.Append(((IArrayFieldInfoDescriptor)fieldDescriptor).ArrayToString(
                                      (IEnumerable <dynamic>)keyValuePair.Value));
                        continue;
                    }

                    sb.Append(((IFixedFieldInfoDescriptor)fieldDescriptor).RecordToString(keyValuePair.Value));
                }
                AfterFluentWriteEventArgs afterWriteArgs = OnAfterWriteRecord(expandoObject, lineNumber, sb.ToString());

                await writer.WriteLineAsync(afterWriteArgs.Line);

                if (flush)
                {
                    await writer.FlushAsync();
                }
                lineNumber++;
            }
        }
        public override async Task <ExpandoObject[]> ReadStreamAsync(StreamReader reader)
        {
            IList <ExpandoObject> items = new List <ExpandoObject>();
            string currentLine          = await reader.ReadLineAsync();

            int currentLineNumber = 1;

            while (currentLine != null)
            {
                if (!string.IsNullOrWhiteSpace(currentLine))
                {
                    BeforeFluentReadEventArgs beforeReadArgs = OnBeforeReadRecord(currentLine, currentLineNumber);
                    if (!beforeReadArgs.SkipRecord)
                    {
                        if (beforeReadArgs.LineChanged)
                        {
                            currentLine = beforeReadArgs.Line;
                        }
                        MultiRecordItem recordItem = GetLineDescriptor(currentLine);
                        if (recordItem != null)
                        {
                            ExpandoObject item = await ReadLineAsync(currentLine, recordItem.Descriptor);

                            AfterFluentReadEventArgs afterReadArgs = OnAfterReadRecord(currentLine, currentLineNumber, item);

                            items.Add(afterReadArgs.Record);
                        }
                    }
                }

                currentLineNumber++;
                currentLine = await reader.ReadLineAsync();
            }

            return(items.ToArray());
        }