Skip to content

SAIF.Framework.Common.Files architecture

SAIF.Framework.Common.Files (project folder Common\SAIF.Common.Files, root namespace SAIF.Common.Files) is a .NET Framework 4.6.2 class library containing two cohesive, mutually independent subsystems — an attribute/fluent-configuration-driven flat-file reader/writer and an ASC X12 EDI object model — that share only the IParser<T> contract and a dependency on the SAIF.Framework.Common package.

Responsibilities

  • Read and write delimited (CSV, tab-delimited, custom-delimiter) and fixed-width flat files by mapping file rows to POCO record types via declarative attributes or a fluent, code-first configuration API.
  • Model, parse, build, and serialise ASC X12 EDI interchange files, including the envelope hierarchy (interchange → functional group → transaction set → hierarchical transaction → hierarchical level) and ~40 strongly-typed segment classes for healthcare transactions (837 claim, 835 remittance, 277 claim status, 997/999 acknowledgement)*.
  • Provide a shared, minimal IParser<T> contract (List<T> Parse(string)) used by both the flat-file record parsing path and the EDI segment/element parsers.
  • Delegate cross-cutting utility behaviour (sequential indexing, argument validation, string/enumerable/expression helpers) to the same-repo SAIF.Framework.Common package rather than reimplementing it.

Component boundaries

  • Flat-file subsystem (SAIF.Common.Files.Core) — a reflection- and attribute-driven mapper between delimited/fixed-width text lines and POCO record types.
  • Declaration layer (Core\Attributes\): FormatBase and concrete attributes (Csv, TabDelimited, DelimitedBy, FixedFormat, DelimitedLayout, FixedLayout) declare format and per-property layout.
  • Configuration layer (Core\Configurations\): FileConfiguration/FileConfiguration<T>, FileRecordLayout, and FileLayoutBuilder hold the runtime layout model and expose an alternative fluent (code-first) configuration path.
  • Engine layer (Core\FileReader.cs, Core\FileWriter.cs): static generic classes that discover configurations, prepare Microsoft.VisualBasic.FileIO.TextFieldParser, and iterate/build records. Both privately re-implement an identical attribute-scan method (GetFileConfigurations()), which is duplicated rather than shared.*
  • Record model (Core\Record.cs, TabDelimitedRecord.cs, Field.cs): Record, TabDelimitedRecord, and Field carry the raw Value/Index data.
  • EDI subsystem (SAIF.Common.Files.Edi and nested Edi.Core.* / Edi.Segments) — an object model over ASC X12 interchange files.
  • Entry/facade: EdiManager.File() → IEdiFileBuilder/EdiFileBuilder; .Path(path).Read() / .Write(file) is the sanctioned entry point for file IO.
  • IO layer (Edi\Core\Readers, Edi\Core\Writers): EdiFileReader and EdiFileWriter.
  • Lexical parsing layer (Edi\Core\Parsers): EdiSegmentParser → EdiDataElementParser → EdiCompositeDataElementParser, cascading on ~, *, and : respectively.
  • Structural parsing layer: EdiGroupParser converts a flat, index-ordered segment list into the X12 envelope hierarchy (file → functional groups → transaction sets → hierarchical transactions → hierarchical levels).
  • Domain model (SAIF.Common.Files.Edi): EdiFile, EdiSegment, EdiElement, SegmentGroup, FunctionalGroup, TransactionSet, HierarchialTransaction, HierarchialLevel.
  • Builders (Edi\Core\Builders): SegmentBuilder is the only writer of element indexes; EdiRecordBuilder is the only serialiser.
  • Typed segment layer (Edi\Segments): ~43 typed segment classes implementing ISegmentData (symmetric Build()/Fill()), depending on the element model but never on the parsers or on IO.
  • Shared dependency boundary: both subsystems depend on the same-repo SAIF.Framework.Common NuGet package for Sequence, Enforce, and string/enumerable/expression extensions, but do not depend on each other beyond the shared IParser<T> contract.

Interaction model

  • The domain model never performs file IO itself; IO is isolated in Edi\Core\Readers/Edi\Core\Writers and Core\FileReader/FileWriter.
  • The typed segment layer depends on the element model but never on the parsers or on IO.
  • EdiFile is the one place where the model calls back into a parser (EdiGroupParser.CreateFunctionalGroups) — a lazy-initialisation/cycle point between the model and parser layers.
  • Reading an EDI file: EdiManager.File().Path(p).Read() → EdiFileReader.Read() concatenates all lines into one continuous string → EdiSegmentParser.Parse → cascading element/composite parsers → EdiFile.SetSegments → EdiFile.RefreshGroupings() builds the header/trailer and (when ISA/IEA/GS/GE are all present) the functional-group hierarchy via EdiGroupParser.
  • Writing an EDI file: typed segments produce elements via ISegmentData.Build(); SegmentBuilder assembles ordered elements (rejecting a duplicate identifying element at index 0, omitting nulls); EdiRecordBuilder serialises segments/elements to text, preserving skipped-element ordinals with * placeholders; EdiFileWriter writes the result as a single ~-terminated line, overwriting any existing file.
  • Reading a typed flat file: FileReader<TRecord>.Read discovers FormatBase/layout attributes on TRecord, selects a configuration (single, or the one flagged IsDefault), prepares TextFieldParser accordingly, then iterates rows and builds each record via the layout's readable properties, converters, and the delegated Sequence indexer.
  • Writing a typed flat file: FileWriter<TRecord>.Write performs the same configuration discovery, then serialises an optional header record and each data record through writable layouts, converters, and fixed-width alignment/padding.
  • Both subsystems' parser/reader classes are single-use instances — each parser instance carries its own results list and index sequence.*

Architecture diagram

The following diagram shows the two independent subsystems and their shared dependency on SAIF.Framework.Common.

flowchart TD
  subgraph FlatFile["Flat-file subsystem<br>(SAIF.Common.Files.Core)"]
    Attr["Attributes<br>Csv / TabDelimited /<br>DelimitedBy / FixedFormat<br>DelimitedLayout / FixedLayout"]
    Cfg["Configurations<br>IFileConfiguration /<br>FileConfiguration&lt;T&gt;<br>FileRecordLayout / FileLayoutBuilder"]
    RW["FileReader&lt;TRecord&gt; /<br>FileWriter&lt;TRecord&gt;<br>FileReader (untyped)"]
    Rec["Record model<br>IRecord / Record / IDelimitedRecord<br>TabDelimitedRecord / Field"]
    Attr --> Cfg
    Cfg --> RW
    RW --> Rec
    RW --> TFP["Microsoft.VisualBasic.FileIO.<br>TextFieldParser"]
  end
  subgraph Edi["EDI subsystem (SAIF.Common.Files.Edi)"]
    Mgr["EdiManager / EdiFileBuilder"]
    IO["EdiFileReader / EdiFileWriter"]
    Parse["Parsers<br>EdiSegmentParser / EdiDataElementParser<br>EdiCompositeDataElementParser<br>EdiGroupParser"]
    Model["Domain model<br>EdiFile / EdiSegment / EdiElement<br>SegmentGroup / FunctionalGroup<br>TransactionSet / HierarchialTransaction<br>HierarchialLevel"]
    Build["Builders<br>SegmentBuilder / EdiRecordBuilder"]
    Seg["Typed segments (ISegmentData)<br>ISA GS ST BHT HL CLP SVC TRN,<br>and 35 more (see API reference)"]
    Mgr --> IO
    IO --> Parse
    Parse --> Model
    Seg --> Build
    Build --> Model
    Model --> Seg
    IO --> Build
  end
  Common["SAIF.Framework.Common (NuGet, same-repo)<br>Sequence / Enforce /<br>string + enumerable +<br>expression extensions"]
  FlatFile --> Common
  Edi --> Common

Sequence diagram

The following diagram shows the primary read/write sequence for an EDI interchange file, from the facade entry point through parsing and grouping.

sequenceDiagram
    participant Caller
    participant EdiManager
    participant EdiFileBuilder
    participant EdiFileReader
    participant EdiSegmentParser
    participant EdiFile
    participant EdiGroupParser
    Caller->>EdiManager: File()
    EdiManager-->>Caller: IEdiFileBuilder
    Caller->>EdiFileBuilder: Path(path).Read()
    EdiFileBuilder->>EdiFileReader: Read()
    EdiFileReader->>EdiFileReader: File.ReadAllLines + concatenate
    EdiFileReader->>EdiSegmentParser: Parse(fileData)
    EdiSegmentParser-->>EdiFileReader: List<IEdiSegment>
    EdiFileReader->>EdiFile: SetSegments(segments)
    EdiFile->>EdiFile: RefreshGroupings()
    EdiFile->>EdiGroupParser: CreateFunctionalGroups(this)
    EdiGroupParser-->>EdiFile: IFunctionalGroupContainer
    EdiFileReader-->>EdiFileBuilder: EdiFile
    EdiFileBuilder-->>Caller: EdiFile

Design constraints

  • DateMaker is declared in namespace SAIF.Common despite living under Edi\Core\, so it appears to consumers as part of the base SAIF.Common namespace rather than the EDI subsystem.*
  • DateTimeBuilder (internal, Edi\Core\Builders\) duplicates DateMaker.MakeDateTime and is never called from live code — dead code.*
  • FileFormats.MultipleRecord is declared but never handled by PrepareParser or any writer branch — an unimplemented format.
  • IEdiEntity, IDataElementBuilder, Areas, RequirementDesignator, RelationalCondition, DataElementType, SegmentGroupType are declared but not referenced by any live code in this library — reserved/unused contracts.*
  • No type in this library derives from a BOF base class (clsBusinessBase, clsBusinessCollectionBase, AppManager), and none derives from an NHibernate, Autofac, or console-framework base type.
  • Nothing in the library depends on configuration files, a database, a service container, or an identity/authorization API — configuration, security/authorization, and database interactions were all found to be none.
  • The library ships its own C# source under src via its .nuspec (<files><file src="**\*.cs" exclude="packages\**\*.*;obj\**\*.*" target="src"/></files>), and IncludeReferencedProjects = true has no additional bundling effect because the .csproj declares no <ProjectReference> elements; SAIF.Framework.Common is consumed purely as a package dependency.

Note: Statements marked with * were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts.

Sources

  • Common\SAIF.Common.Files\SAIF.Framework.Common.Files.csproj
  • Common\SAIF.Common.Files\Core\FileReader.cs
  • Common\SAIF.Common.Files\Core\FileWriter.cs
  • Common\SAIF.Common.Files\Edi\EdiManager.cs
  • Common\SAIF.Common.Files\Edi\EdiFile.cs
  • Common\SAIF.Common.Files\Edi\Core\Readers\EdiFileReader.cs
  • Common\SAIF.Common.Files\Edi\Core\Writers\EdiFileWriter.cs
  • Common\SAIF.Common.Files\Edi\Core\Parsers\EdiSegmentParser.cs
  • Common\SAIF.Common.Files\Edi\Core\Parsers\EdiGroupParser.cs
  • Common\SAIF.Common.Files\Edi\Core\Builders\SegmentBuilder.cs
  • Common\SAIF.Common.Files\Edi\Core\Builders\EdiRecordBuilder.cs
  • Common\SAIF.Common.Files\Edi\Core\DateMaker.cs
  • Common\SAIF.Common.Files\Edi\Core\Builders\DateTimeBuilder.cs
  • Common\SAIF.Common.Files\Core\Enums.cs
  • Common\SAIF.Common.Files\Edi\IEdiEntity.cs
  • Common\SAIF.Common.Files\Edi\Core\Builders\IDataElementBuilder.cs
  • Common\SAIF.Common.Files\Edi\enums.cs