---
title: SAIF.Framework.Core architecture
summary: Architectural responsibilities, boundaries, and interaction patterns.
status: draft
owner: <owner>
last_reviewed: 2026-09-15
library: SAIF.Framework.Core
reference_type: package
---

# SAIF.Framework.Core architecture

SAIF.Framework.Core is the root library of the SAIF.Framework.* family: a cross-cutting platform framework (not a business-domain library) that defines the environment/configuration abstraction (`IEnvironmentService`/`EnvironmentServiceBase` and its four concrete subclasses), a first-class Active Directory provider (`ADService`/`MachineSecurityService`), WCF/REST-fronted platform services (security, document, fax, imaging, PDF, print, preference, UC4, work-calendar, user-profile), a generic repository/unit-of-work data-access contract, and an Autofac-based composition root that other Framework4 libraries and consuming applications build on.

## Responsibilities
- Define and implement the environment/configuration abstraction (`IEnvironmentService`, `EnvironmentServiceBase`) consumed by nearly every concrete service in this library and by downstream Framework4 libraries and applications, including layered configuration resolution (developer-override JSON → in-memory cache → Environment API section fetch).
- Provide a first-class Active Directory provider (`ADService`) performing direct `System.DirectoryServices(.AccountManagement)` group-membership lookups, and a machine-authorization façade (`MachineSecurityService`) used specifically to gate `IsDeveloperMachine`.
- Front two external, configurable security back ends behind framework-owned façades: a WCF `SecurityService` (via internal `SecurityServiceClient`, exposed through `SecurityGroupService`/`SystemUserProfile`) and a REST Security API (via `SecurityApiClient`).
- Define a generic data-access abstraction (`IUnitOfWork`, `IRepository<TEntity>`, `IRepositoryFactory`, `ISessionHelper`) for downstream Framework4 libraries and applications to implement against real data stores; this library ships only an in-memory `TestRepository`/`TestUnitOfWork` test double, no production implementation.
- Implement concrete platform services (validation, document generation, fax, imaging, PDF, print, preference, UC4, work-calendar, user-profile, email, logging) each backed by a WCF/REST client proxy, so application code depends only on framework interfaces rather than on WCF channel plumbing.
- Supply an Autofac composition root (`ServiceRegistrations.RegisterCoreServicesForWeb` / `RegisterCoreServicesForWindows`) that consuming web or Windows applications call at startup to wire the above services into a `ContainerBuilder`.

## Component boundaries
- **Contracts (`Core.Contracts.*`)**: plain DTOs shared across the platform (address/person/company, configuration, security, imaging, PDF, menu, UC4, web context) — no behavior, consumed by every other layer.
- **Service interfaces (`Core.Services.*`)**: the public seams applications and other libraries code against (`IEnvironmentService`, `IValidationService`, `IUserProfileService`, `IDocumentService`, `IMachineSecurityService`, `ISecurityApiClient`, `ISecurityGroupService`, etc.).
- **Environment/configuration (`Services.Common.*`)**: resolves per-host/per-track configuration, developer-machine detection, secure-setting caching, and DB connection-string resolution (`EnvironmentServiceBase`, `DbConnectionManager`, `SecureSettingCache`, `EnvironmentConfigKeys`).
- **Data access abstraction (`Data.*`)**: generic repository/unit-of-work contract plus entity model (`IUnitOfWork`, `IRepository<TEntity>`, `Data.Model.*`); no concrete production implementation is shipped, only an in-memory test double.
- **Concrete services (`Services.Utilities.*`, `Services.*`)**: implements the service interfaces against WCF/REST backends (`FaxService`, `PDFService`, `SecurityApiClient`, `UserProfileService`, `FluentValidationService`, `SecurityGroupService`).
- **WCF/SOAP transport (`Services.ClientProxies.*`, `Services.WCF.*`, generated `Service References\*`)**: encapsulates channel creation/disposal/error handling for legacy SOAP/WCF endpoints (`DisposableClientBase<TChannel>`, internal `SecurityServiceClient`, legacy `DocumentServiceProxy`/`ActiveDirectoryServiceProxy`).
- **Cross-cutting (`Services.Extensions`, `Services.OpenTelemetry`, `log4netAppenders`)**: extension helpers, OpenTelemetry tracing wiring, and a custom log4net appender that posts to a REST logging API.
- **Composition root**: `ServiceRegistrations` wires the above via Autofac (`RegisterCoreServicesForWeb`/`RegisterCoreServicesForWindows`), called by consuming application startup code outside this repository.

## Interaction model
- `EnvironmentServiceBase` is the architectural hub: nearly every concrete service (`SecurityServiceClient`, `SecurityApiClient`, `DbConnectionManager`, `DocumentService`, `PdfConvertAndMergeService`, `UserProfileService`, and others) takes an `IEnvironmentService` in its constructor and calls `GetConfigSetting(...)` to resolve endpoint URLs, LDAP roots, and file paths. There is no static/global configuration reader outside this seam except a small number of bootstrap-only direct `ConfigurationManager.AppSettings[...]` reads inside `EnvironmentServiceBase` itself (`ApplicationHost`, `EnvApiDeveloperSettingsOverride`).
- `MachineSecurityService` → `ADService` is a private, in-process AD path used only to answer "is this machine a developer machine" (`EnvironmentServiceBase.IsDeveloperMachine`), separate from the WCF-fronted `SecurityServiceClient`/`SecurityGroupService` path and from the REST-fronted `SecurityApiClient` path — three distinct, non-unified authorization mechanisms coexist behind different framework façades.
- Authorization architecture is mixed: (a) a centralized WCF `SecurityService` fronted by internal `SecurityServiceClient` and exposed via `SecurityGroupService`/`SystemUserProfile`; (b) a parallel REST Security API fronted by `SecurityApiClient`; (c) direct in-process AD lookups via `ADService`/`MachineSecurityService` for the narrow developer-machine use case. None of these implement per-request result caching — each call re-invokes the backing WCF/REST/LDAP call. See [Security and authorization](security-authorization.md) for the full catalog.
- Concrete document/fax/imaging/PDF/print services each wrap a WCF or legacy ASMX client proxy (`Services.ClientProxies.*`, `Services.WCF.*`), so the framework, not the application, owns channel lifetime and error handling (`DisposableClientBase<TChannel>`).
- Validation flows through `FluentValidationService`, which resolves `IValidator<T>` via an Autofac-backed `ValidatorFactory` and always additionally executes the `"AuthorizationRules"` FluentValidation rule set as a side effect of the default `Validate<T>(T)` call (result currently discarded — see Design constraints, and [BR-CORE-11](business-rules.md#br-core-11-authorizationrules-side-effect-execution)).
- The Autofac composition root (`ServiceRegistrations`) is invoked once by a consuming web or Windows application at startup; it registers the interfaces above (plus every FluentValidation validator discovered via assembly scanning) at `InstancePerRequest` (web) or `InstancePerLifetimeScope` (Windows) lifetime scope.

## Architecture diagram
The following diagram shows the high-level component boundaries and their interaction through the environment-service hub.

```mermaid
flowchart TD
	App[Consuming application] --> Reg["ServiceRegistrations<br>Autofac composition root"]
	Reg --> Env["EnvironmentServiceBase<br>+ 4 concrete subclasses"]
	Env --> ConfigAPI["Environment API<br>external"]
	Env --> AppConfig["ConfigurationManager.AppSettings<br>bootstrap-only"]

	Env --> MachineSec[MachineSecurityService]
	MachineSec --> AD["ADService<br>System.DirectoryServices"]

	Env --> SecGroup[SecurityGroupService]
	SecGroup --> WCFSecClient["SecurityServiceClient<br>internal, WCF"]
	WCFSecClient --> WCFSec["WCF SecurityService<br>external"]

	Env --> RestSec[SecurityApiClient]
	RestSec --> RestAPI["REST Security API<br>external"]

	Env --> DocSvcs["Document / Fax / Imaging /<br>PDF / Print services"]
	DocSvcs --> WCFDoc["WCF/SOAP endpoints<br>external"]

	Env --> DbMgr[DbConnectionManager]
	DbMgr --> DbProxy["DbConnectionServiceProxy<br>legacy ASMX/WCF"]

	Env --> Validation[FluentValidationService]
	Validation --> ValidatorFactory["ValidatorFactory<br>Autofac-backed"]

	DataAbs["IUnitOfWork / IRepository&lt;TEntity&gt;<br>abstraction only"] -.->|implemented downstream| App
```

## Sequence diagram
The following diagram shows the primary resource-membership authorization sequence used by `SecurityGroupService.GetMembersByResource`.

```mermaid
sequenceDiagram
	participant Caller as Consuming application
	participant SGS as SecurityGroupService
	participant Env as IEnvironmentService
	participant WCFClient as SecurityServiceClient (internal)
	participant WCFSvc as WCF SecurityService (external)

	Caller->>SGS: GetMembersByResource(resourceName, recurse, includeDisabled)
	SGS->>SGS: Normalize suffix (Resource/TestResource) per Env.IsProduction
	SGS->>Env: GetConfigSetting("securityServiceUrl", "ad.ldap.host", ...)
	Env-->>SGS: Resolved endpoint/LDAP settings
	SGS->>WCFClient: new SecurityServiceClient(env)
	WCFClient->>WCFSvc: GetUsersByGroup(resourceName, ldap, domain, recurse, includeDisabled)
	WCFSvc-->>WCFClient: string[] member usernames
	WCFClient-->>SGS: string[] member usernames
	SGS-->>Caller: string[] member usernames
```

## Design constraints
- The generic data-access abstraction (`IUnitOfWork`/`IRepository<TEntity>`) has no production implementation in this library — only an in-memory `TestRepository`/`TestUnitOfWork` test double — so consumers or other Framework4 libraries must supply the real implementation; this library defines the contract only.
- The `SAIF.Common` namespace (`EntityBase<TEntity>`, `IDataEntity`, `Enforce`, `LongSequence`, `Extensions.*`) is referenced pervasively but has no confirmed `<PackageReference>`/`<ProjectReference>` in this project or its `.nuspec` — presumed transitive through `SAIF.HashUtil` or `SAIF.Web.API.Clients` (both confirmed internal NuGet packages on the SAIFNuget feed, but neither is indexed by the Legends CLI, so their own dependency graphs remain unknown**), and this transitive path is unconfirmed.*
- Three authorization mechanisms coexist without a unifying interface: WCF `SecurityService` (`ISecurityGroupService`/`SystemUserProfile`), REST Security API (`ISecurityApiClient`), and direct in-process AD (`IMachineSecurityService`) — consumers must choose the correct mechanism per use case; none cache results per request.
- `FluentValidationService.Validate<T>(T)` always additionally executes the `"AuthorizationRules"` rule set as a side effect, but discards its result — flagged as an open question (unclear whether intentional warm-up/caching behavior or a latent defect where authorization-rule failures are silently ignored).*
- Internal WCF client wrapper classes (e.g., `SecurityServiceClient`) are deliberately marked `internal` and are not meant to be consumed directly by application code — callers must go through the higher-level façades (`SecurityGroupService`, `SystemUserProfile`).
- The legacy ASMX `ActiveDirectoryServiceProxy.HasAccess` path has no in-repo caller and is flagged as likely-dead legacy code retained for backward compatibility, not an active enforcement path.*
- Developer-machine detection is gated by a hostname tag-number pattern (`^[TV]\d+$`) before any AD lookup occurs, and developer local JSON overrides always take precedence over environment-API-sourced and in-memory cached configuration values.
- Every `IsAuthorized2`-style dual-domain check declared on the WCF `ISecurityService` contract is forwarded 1:1 by `SecurityServiceClient` but has no caller within this library — only single-domain `IsAuthorized` is exercised internally.*

## Related documentation
- [Index](index.md)
- [Overview](overview.md)
- [Dependencies](dependencies.md)
- [Configuration](configuration.md)
- [Operations and processes](operations-processes.md)
- [Business rules](business-rules.md)
- [Security and authorization](security-authorization.md)
- [API reference](api/index.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming conventions, or
> contextual evidence where direct confirmation was not available in source artifacts. Statements
> marked with `**` could not be confirmed; treat as unknown until verified.

## Sources
- `Core\SAIF.Core\SAIF.Framework.Core.csproj`
- `Core\SAIF.Core\SAIF.Framework.Core.nuspec`
- `Core\SAIF.Core\app.config`
- `Core\SAIF.Core\Core\Services\ADService.cs`
- `Core\SAIF.Core\Core\Services\MachineSecurityService.cs`
- `Core\SAIF.Core\Core\Services\IEnvironmentService.cs`
- `Core\SAIF.Core\Services.Common\EnvironmentServiceBase.cs`
- `Core\SAIF.Core\Services.Common\DbConnectionManager.cs`
- `Core\SAIF.Core\Services.Common\EnvironmentConfigKeys.cs`
- `Core\SAIF.Core\Services.Common\WindowsEnvironmentService.cs`
- `Core\SAIF.Core\Services.Common\WcfEnvironmentService.cs`
- `Core\SAIF.Core\Services.Common\CustomEnvironmentService.cs`
- `Core\SAIF.Core\Services.Common\WebEnvironmentService.cs`
- `Core\SAIF.Core\Services.Common\SecureSettingCache.cs`
- `Core\SAIF.Core\Services\ServiceRegistrations.cs`
- `Core\SAIF.Core\Services\ServiceBase.cs`
- `Core\SAIF.Core\Services\ValidatorFactory.cs`
- `Core\SAIF.Core\Services\SecurityGroupService.cs`
- `Core\SAIF.Core\Services\ClientProxies\SecurityServiceClient.cs`
- `Core\SAIF.Core\Services\Utilities\SecurityApiClient.cs`
- `Core\SAIF.Core\Services\Utilities\FluentValidationService.cs`
- `Core\SAIF.Core\Services\Utilities\LogService.cs`
- `Core\SAIF.Core\Services\Utilities\Documents\DocumentService.cs`
- `Core\SAIF.Core\Services\Utilities\Documents\PdfConvertAndMergeService.cs`
- `Core\SAIF.Core\Services\Utilities\Documents\FaxService.cs`
- `Core\SAIF.Core\Services\Utilities\UserProfile\UserProfileService.cs`
- `Core\SAIF.Core\Services\Utilities\UserProfile\ApplicationUserProfileBase.cs`
- `Core\SAIF.Core\Services\Utilities\UserProfile\SystemUserProfile.cs`
- `Core\SAIF.Core\Services.WCF\Contracts\ISecurityService.cs`
- `Core\SAIF.Core\Services.WCF\ClientProxies\DisposableClientBase.cs`
- `Core\SAIF.Core\Data\Interfaces\IUnitOfWork.cs`
- `Core\SAIF.Core\Data\Interfaces\ISessionHelper.cs`
- `Core\SAIF.Core\Data\Interfaces\Repositories\IRepository.cs`
- `Core\SAIF.Core\Data\Interfaces\Repositories\IRepositoryFactory.cs`
- `Core\SAIF.Core\Data\TestRepository\TestRepository.cs`
- `Core\SAIF.Core\Data\TestRepository\TestUnitOfWork.cs`
- `Core\SAIF.Core\Data\TestRepository\TestSessionHelper.cs`
- `Core\SAIF.Core\Services\ClientProxies\Legacy\ActiveDirectoryServiceProxy.cs`
