Skip to content

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 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).
  • 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.

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.

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.*

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