SAIF .NET Core Framework — Architecture¶
Overview¶
This repository is a mono-repo containing all of the independently-versioned, independently-built class libraries that together make up the SAIF .NET Core (net6.0/net8.0) application framework. Each folder under src/ is one framework component and is published as its own NuGet package via its own pipeline (see Pipelines.md). There are no project-to-project references between these components — every dependency between the libraries is a NuGet package reference, resolved at build time from the SAIF NuGet feed, exactly as when each component lived in its own repository. Consolidating into one repository changes where the source lives and how it is reviewed; it does not change the packaging or dependency model.
The framework is organized into three conceptual layers:
SAIF.NetCore.ServiceContracts— the foundation layer. Contains shared interfaces and POCO/primitive types used across the framework (e.g. request/response contracts, common abstractions). It has no dependencies on any other SAIF package — it only depends on third-party/framework packages (e.g.Microsoft.IdentityModel.Tokens,Microsoft.AspNetCore.App). Every other library sits on top of it.
SAIF.NetCore.Common plays a similar "no SAIF dependencies" role, providing shared extension methods, enums, and common types that any library (including contracts consumers) can use without pulling in the rest of the framework.
-
Implementation libraries — the middle layer. Each of these packages implements one focused capability (auth, logging, DB connectivity, HTTP clients, messaging, etc.). They reference
ServiceContracts(and sometimesCommon) to implement the shared interfaces/POCOs, but they do not reference each other's source — any cross-library reuse is itself just another NuGet package reference. In practice, most implementation libraries only depend onServiceContracts, but a small number take a NuGet dependency on another implementation package when it makes sense to reuse a capability (see "Notable exceptions" below). -
SAIF.NetCore.ServiceExtensions— the parent-most / top layer. Consuming applications only need to add a reference to this single NuGet package to get access to all SAIF services. It contains ASP.NET Core startup base classes andIServiceCollection/IApplicationBuilderextension methods that wire the contracts and implementations together (dependency injection registration, middleware, OpenTelemetry, auth, etc.). It references bothServiceContractsand the implementation packages it composes.
Notable exceptions (implementation → implementation)¶
A few implementation packages take a direct NuGet dependency on another implementation package rather than only on ServiceContracts, because they build on that package's capability:
SAIF.NetCore.NtlmApiAuth→SAIF.NetCore.AuthServiceSAIF.NetCore.SystemHash→SAIF.NetCore.HashUtilSAIF.NetCore.Services.Messaging→SAIF.NetCore.Logging,SAIF.NetCore.PingableService
These are still package references, not source/project references — each component remains independently buildable and versioned, even though the source now lives side by side in this repository.
Components in this repository¶
Folder (src/...) |
NuGet package | Role |
|---|---|---|
src/SAIF.NetCore.ServiceContracts |
SAIF.NetCore.ServiceContracts |
Foundation: shared interfaces & POCOs |
src/SAIF.NetCore.Common |
SAIF.NetCore.Common |
Foundation: shared enums/extensions/types |
src/SAIF.NetCore.AuthService |
SAIF.NetCore.AuthService |
Implementation: authentication |
src/SAIF.NetCore.DbConnectionClient |
SAIF.NetCore.DBConnectionClient |
Implementation: DB connection client |
src/SAIF.NetCore.EnvironmentClient |
SAIF.NetCore.EnvironmentClient |
Implementation: environment/config client |
src/SAIF.NetCore.ErrorHandler |
SAIF.NetCore.ErrorHandler |
Implementation: centralized error handling |
src/SAIF.NetCore.HashUtil |
SAIF.NetCore.HashUtil |
Implementation: hashing utilities |
src/SAIF.NetCore.HttpClients |
SAIF.NetCore.HttpClients |
Implementation: HTTP client helpers |
src/SAIF.NetCore.LegacyAuth |
SAIF.NetCore.LegacyAuth |
Implementation: legacy authentication support |
src/Messaging |
SAIF.NetCore.Services.Messaging |
Implementation: messaging/queue services |
src/SAIF.NetCore.Nhibernate |
SAIF.NetCore.NHibernate |
Implementation: NHibernate data access |
src/SAIF.NetCore.NtlmApiAuth |
SAIF.NetCore.NtlmApiAuth |
Implementation: NTLM API authentication |
src/SAIF.NetCore.OIDC |
SAIF.NetCore.OIDC |
Implementation: OpenID Connect support |
src/SAIF.NetCore.PingableService |
SAIF.NetCore.PingableService |
Implementation: health/ping endpoints |
src/SAIF.NetCore.Logging |
SAIF.NetCore.Logging |
Implementation: logging |
src/SAIF.NetCore.SystemHash |
SAIF.NetCore.SystemHash |
Implementation: system hashing |
src/SAIF.NetCore.Clients.UC4 |
SAIF.NetCore.Clients.UC4 |
Implementation: UC4/Automic client |
src/SAIF.NetCore.WindowsService |
SAIF.NetCore.WindowsService |
Implementation: Windows Service hosting |
src/SAIF.NetCore.ServiceExtensions |
SAIF.NetCore.ServiceExtensions |
Top layer: app startup/DI wiring, consumed directly by applications |
Architecture Diagram¶
All arrows are dashed to emphasize that every dependency shown is a NuGet package reference, never a project/source reference. Implementation libraries are grouped into themed subgraphs purely for readability — libraries within the same subgraph do not depend on one another (except where an explicit arrow says otherwise).
flowchart TB
%% Foundation layer
subgraph Foundation["Foundation layer (no SAIF dependencies)"]
direction LR
SC["SAIF.NetCore.ServiceContracts"]
COMMON["SAIF.NetCore.Common"]
end
%% Implementation layer, split into themed groups so no single row gets too wide
subgraph AuthGroup["Auth & Identity"]
direction LR
AUTH["SAIF.NetCore.AuthService"]
NTLM["SAIF.NetCore.NtlmApiAuth"]
LEGACY["SAIF.NetCore.LegacyAuth"]
OIDC["SAIF.NetCore.OIDC"]
end
subgraph DataGroup["Data, Messaging & Ops"]
direction LR
DB["SAIF.NetCore.DBConnectionClient"]
NH["SAIF.NetCore.NHibernate"]
MSG["SAIF.NetCore.Services.Messaging"]
PING["SAIF.NetCore.PingableService"]
LOG["SAIF.NetCore.Logging"]
end
subgraph UtilGroup["Utilities & Infra"]
direction LR
ENV["SAIF.NetCore.EnvironmentClient"]
ERR["SAIF.NetCore.ErrorHandler"]
HASH["SAIF.NetCore.HashUtil"]
SYSHASH["SAIF.NetCore.SystemHash"]
HTTP["SAIF.NetCore.HttpClients"]
UC4["SAIF.NetCore.Clients.UC4"]
WINSVC["SAIF.NetCore.WindowsService"]
end
%% Top layer
SE["SAIF.NetCore.ServiceExtensions (startup base classes & DI extensions)"]
APP["Consuming Application"]
%% Each themed group depends on the foundation (NuGet package references)
AuthGroup -.-> Foundation
DataGroup -.-> Foundation
UtilGroup -.-> Foundation
%% Notable implementation-to-implementation NuGet references
NTLM -.->|NuGet ref| AUTH
SYSHASH -.->|NuGet ref| HASH
MSG -.->|NuGet ref| LOG
MSG -.->|NuGet ref| PING
%% ServiceExtensions composes contracts + implementations
SE -.-> Foundation
SE -.-> AuthGroup
SE -.-> DataGroup
SE -.-> UtilGroup
%% Applications consume ServiceExtensions
APP -.->|NuGet ref| SE
Key Takeaways¶
- Direction of dependency is strictly bottom-up:
ServiceContracts/Common→ implementation libraries →ServiceExtensions→ applications. Nothing in a lower layer ever references a higher layer. - All cross-component dependencies are NuGet package references, not project references — each component still builds, versions, and ships independently even though its source lives in this shared repository.
- Implementation libraries are siblings: by convention they depend only on the foundation layer, not each other, keeping them independently swappable. The small set of exceptions listed above are intentional NuGet dependencies where one capability is built directly on another.
- Applications only need to reference
SAIF.NetCore.ServiceExtensionsto pull in the full set of startup wiring for the SAIF framework; the transitive NuGet graph brings in the implementation packages andServiceContractsautomatically. - This repository replaced 19 standalone repositories (each named
Framework.NCore.<Component>) as part of a mono-repo migration; seePipelines.mdfor the current per-component pipeline setup.