Skip to content

SAIF.Framework.Common architecture

SAIF.Framework.Common is a foundation utility library at the lowest tier of the SAIF .NET Framework 4 stack. It has zero outbound dependencies on other SAIF assemblies or third-party packages, which makes it safely referenceable by any layer above it. Its responsibility is to supply cross-cutting primitives: date/date-range semantics, string normalization and casing, validation result modelling, argument guards, sequence generation, serialization helpers, exception formatting, and logging contracts (Stage 1 analysis, "Responsibility boundary").

Responsibilities

  • Supply fail-fast argument/precondition guards (Enforce, ValidatedNotNullAttribute, GenericExtensions.IsNull/IfNullThrow) (Stage 1 analysis, "Functional groupings").
  • Represent and reason about date intervals — validity, overlap, contiguity, open-endedness, membership — plus EDI/Julian date encoding (IDateRange, DateRange, NullableDateRange, DateRangeExtensions, DateExtensions, DateMaker, Julian) (Stage 1 analysis, "Functional groupings").
  • Normalize and classify text: casing, truncation, character-class filtering, Unicode→ASCII folding, truthy-string parsing, decimal precision (StringExtensions, StringUtilities, TitleCase, BooleanExtensions, NumericExtensions) (Stage 1 analysis, "Functional groupings").
  • Model validation outcomes and surface them as an exception (IValidationResult, ValidationResult, IValidationFailure, ValidationFailure, SaifValidationException) (Stage 1 analysis, "Functional groupings").
  • Carry contextual (view-routing) exception information for a consuming presentation layer (ContextException and its four subclasses) (Stage 1 analysis, "Functional groupings").
  • Provide in-memory monotonic sequence generators (ISequenceGenerator<T>, SequenceGenerator<T>, Sequence, LongSequence) (Stage 1 analysis, "Functional groupings").
  • Provide JSON/XML serialization round-tripping, stream-to-byte-array conversion, MD5 hashing, and binary header search (Serializer, GenericExtensions.ToJsonString/ToXmlString, DotNet40Extensions, FileExtensions, ByteExtensions) (Stage 1 analysis, "Functional groupings").
  • Define — but not implement — console/file logging contracts and format exception chains for logs (ILogWriter, IConsoleLogService, LogType, ExceptionExtensions) (Stage 1 analysis, "Functional groupings").
  • Provide strongly-typed reflection helpers for property discovery and assignment (Reflector, ExpressionExtensions) (Stage 1 analysis, "Functional groupings").
  • Provide empty marker contracts for downstream data-entity types (IDataEntity, EntityBase<TEntity>) (Stage 1 analysis, "Functional groupings").
  • Parse ASP.NET MVC-style route segments from a Uri and split DOMAIN\user identity names (UriExtensions, SecurityPrincipalExtensions) (Stage 1 analysis, "Functional groupings").
  • Fill LINQ/collection gaps: ForEach, None, TakeFromEnd, keyed Distinct, full/left outer joins, dictionary merge/upsert (IEnumerableExtensions, DictionaryExtensions) (Stage 1 analysis, "Functional groupings").

Component boundaries

  • Guard / precondition layer: Enforce, ValidatedNotNullAttribute, GenericExtensions.IsNull/IfNullThrow — fail-fast argument validation; throws ArgumentNullException/ArgumentException/caller-supplied exception types (Stage 1 analysis, "Functional groupings (layers within the library)").
  • Date & date-range domain: IDateRange, IDateRangeList, DateRange, NullableDateRange, DateRangeExtensions, DateExtensions, IComparableExtensions, DateMaker, Julian, DateRangeOverlapResult, IncludeComparisons, ContiguousOptions, OverlappingDateOptions — represents and reasons about date intervals (Stage 1 analysis, same section).
  • String & text normalization: StringExtensions, StringUtilities, TitleCase, BooleanExtensions, NumericExtensions — casing, truncation, character-class filtering, Unicode→ASCII folding, truthy-string parsing, decimal precision (Stage 1 analysis, same section).
  • Validation modelling: IValidationResult, ValidationResult, IValidationFailure, ValidationFailure, SaifValidationException — accumulates property-level failures and surfaces them as an exception (Stage 1 analysis, same section).
  • Contextual (view) exceptions: ContextException + 4 subclasses — carries a TargetView name and a Model payload so an MVC-style presentation layer can route to a specific error view* (Stage 1 analysis, same section).
  • Sequence generation: ISequenceGenerator<T>, SequenceGenerator<T>, Sequence, LongSequence — in-memory monotonic counters (Stage 1 analysis, same section).
  • Serialization: Serializer, GenericExtensions.ToJsonString/ToXmlString, DotNet40Extensions, FileExtensions, ByteExtensions — JSON (JavaScriptSerializer) and XML (XmlSerializer) round-tripping to/from files and strings; stream→byte[]; MD5 hashing; binary header search (Stage 1 analysis, same section).
  • Diagnostics / logging contracts: ILogWriter, IConsoleLogService, LogType, ExceptionExtensions — define (but do not implement) console/file logging; format exception chains for logs (Stage 1 analysis, same section).
  • Reflection helpers: Reflector, ExpressionExtensions — strongly-typed property discovery and assignment (Stage 1 analysis, same section).
  • Entity markers: IDataEntity, EntityBase<TEntity> — empty marker contracts for downstream data-entity types (Stage 1 analysis, same section).
  • Web/URL helpers: UriExtensions, SecurityPrincipalExtensions — parse ASP.NET MVC-style route segments from a Uri; split DOMAIN\user identity names (Stage 1 analysis, same section).
  • Collection helpers: IEnumerableExtensions, DictionaryExtensions — LINQ gap-fillers: ForEach, None, TakeFromEnd, keyed Distinct, full/left outer joins, dictionary merge/upsert (Stage 1 analysis, same section).

Interaction model

  • The library is stateless and synchronous. It exposes no long-lived services, no I/O ports other than explicit file paths passed by the caller (Serializer.LoadFromJson, SaveToXml, DotNet40Extensions.LoadFromJson, and ILogWriter.FilePath, which is implemented elsewhere), and no network, database, or configuration access (Stage 1 analysis, "Data and control flow").
  • All control flow is caller-driven: a consumer calls a static method or extension method, the method computes a result or throws, and returns (Stage 1 analysis, "Data and control flow").
  • The only mutable state is the CurrentValue field held by a SequenceGenerator<T> instance and the collections held by a ValidationResult instance (Stage 1 analysis, "Data and control flow").
  • There are no outbound cross-layer dependencies. Inbound, the library is designed to be consumed by SAIF application and component layers, evidenced by the ASP.NET MVC-shaped helpers (UriExtensions.ControllerAndActionName defaults to "Home/Index", ContextException.TargetView), the console-logging contracts (IConsoleLogService), and the EDI/Julian date encoders that target mainframe file interchange formats* (Stage 1 analysis, "Cross-layer dependencies").
  • ILogWriter and IConsoleLogService have no implementations in this library — they are contracts intended for consumers/other libraries to implement (Stage 1 analysis, "Interfaces (contracts)").

Architecture diagram

The following diagram shows the library's internal functional groups, their intra-library couplings, the consuming applications outside this repository, and the .NET Framework 4.6.2 BCL surfaces they call into (Stage 1 analysis, "Architecture diagram").

flowchart TD
    subgraph Consumers["Consuming applications / components (outside this repo)"]
        C1["MVC / Web apps"]
        C2["Console batch apps"]
        C3["Component libraries"]
    end

    subgraph Lib["SAIF.Framework.Common (assembly)"]
        G["Guards<br>Enforce, GenericExtensions"]
        D["Date domain<br>IDateRange, DateRange,<br>DateRangeExtensions,<br>DateMaker, Julian, NullableDateRange"]
        S["Text<br>StringExtensions,<br>StringUtilities, TitleCase"]
        V["Validation<br>IValidationResult, ValidationResult,<br>ValidationFailure,<br>SaifValidationException"]
        X["Context exceptions<br>ContextException + subclasses"]
        Q["Sequences<br>ISequenceGenerator, SequenceGenerator,<br>Sequence, LongSequence"]
        Z["Serialization / bytes<br>Serializer, DotNet40Extensions,<br>FileExtensions, ByteExtensions"]
        L["Logging contracts<br>IConsoleLogService, ILogWriter, LogType"]
        R["Reflection<br>Reflector, ExpressionExtensions"]
        W["Web / identity<br>UriExtensions,<br>SecurityPrincipalExtensions"]
        E["Collections<br>IEnumerableExtensions,<br>DictionaryExtensions"]
    end

    subgraph BCL[".NET Framework 4.6.2 BCL"]
        B1["System / System.Core"]
        B2["System.Web.Extensions<br>JavaScriptSerializer"]
        B3["System.Xml<br>XmlSerializer"]
        B4["System.Security.Cryptography / Principal"]
    end

    C1 --> Lib
    C2 --> Lib
    C3 --> Lib

    S --> G
    D --> S
    E --> G
    W --> G
    V --> G
    Z --> B2
    Z --> B3
    Z --> B4
    Lib --> B1

Sequence diagram

The following diagram shows the primary interaction pattern: a caller invokes a static method or extension method, which computes a result synchronously and returns or throws — the library holds no long-lived state beyond a SequenceGenerator<T> instance's CurrentValue or a ValidationResult instance's collections (Stage 1 analysis, "Data and control flow").

sequenceDiagram
    participant Caller
    participant Component as "SAIF.Framework.Common component<br>(static class / extension method)"
    Caller->>Component: Invoke static/extension method
    Component-->>Caller: Return computed result
    Component--xCaller: or throw an exception

Design constraints

  • The library declares zero <ProjectReference> and zero <PackageReference> entries, and its .nuspec declares no <dependencies>; it is a leaf with no in-repo or NuGet dependencies, which is what allows it to be safely referenced from any layer above it (Stage 1 analysis, "Internal (repository) dependencies", "NuGet / package dependencies").
  • There is a circular namespace dependency between SAIF.Common.Extensions and SAIF.Common.Utility: StringExtensions calls TitleCase, and TitleCase calls back into StringExtensions/IEnumerableExtensions. This is legal in a single assembly but is a design coupling worth noting (Stage 1 analysis, "Intra-library coupling").
  • IncludeComparisons is declared twice with identical members (once in SAIF.Common, once in SAIF.Common.Extensions), and ContiguousOptions/OverlappingDateOptions each have a duplicate/near-duplicate nested counterpart in DateRangeExtensions; a consumer importing both namespaces risks compile-time ambiguity or passing the wrong enum type* (Stage 1 analysis, "Duplicate and ambiguous public types").
  • Namespace and folder layout are not aligned: Classes/Enforce.cs declares namespace SAIF; most Classes/*.cs declare SAIF.Common; only ContextException.cs and NullableDateRange.cs declare SAIF.Common.Classes; Interfaces/ likewise splits between SAIF.Common and SAIF.Common.Interfaces* (Stage 1 analysis, "Namespaces", "Duplicate and ambiguous public types").
  • TitleCase is internal while its sibling StringUtilities in the same namespace is public; the title-casing acronym/word lists are therefore reachable only through StringExtensions.ToTitleCase and cannot be extended by a consumer without a source change and rebuild* (Stage 1 analysis, "Duplicate and ambiguous public types").
  • Two areas of behavior depend on ambient runtime state rather than configuration: StringExtensions.ToProperCase/ToTitleCase follow the current thread culture (Thread.CurrentThread.CurrentCulture.TextInfo), and several date operations (DateExtensions.IsCurrentDate/IsFutureDate/IsPastDate, DateRangeExtensions.IsFutureRange/IsPastRange, Julian.GetYear) depend on the server clock and time zone (Stage 1 analysis, "Ambient runtime state consumed").
  • Extensions/DotNet35Extensions.cs exists on disk but has no <Compile Include> entry, so it is excluded from the compiled assembly even though the .nuspec ships it as source, meaning a consumer browsing package sources will see a type that does not exist at runtime* (Stage 1 analysis, "Build and packaging discrepancies", "nuspec contents").
  • No automated test project exists under Common/SAIF.Common/, and SAIF.Framework.Common.sln contains only the one project (Stage 1 analysis, "Unknowns that cannot be resolved from this repository").

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/SAIF.Framework.Common.csproj
  • SAIF.Framework.Common.sln
  • Common/SAIF.Common/Classes/Enforce.cs
  • Common/SAIF.Common/Extensions/StringExtensions.cs
  • Common/SAIF.Common/Utility/TitleCase.cs
  • Common/SAIF.Common/Extensions/DateRangeExtensions.cs
  • Common/SAIF.Common/Classes/DateRange.cs
  • Common/SAIF.Common/Extensions/ExceptionExtensions.cs
  • Common/SAIF.Common/Interfaces/IConsoleLogService.cs
  • Common/SAIF.Common/Interfaces/ILogWriter.cs