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 directSystem.DirectoryServices(.AccountManagement)group-membership lookups, and a machine-authorization façade (MachineSecurityService) used specifically to gateIsDeveloperMachine. - Front two external, configurable security back ends behind framework-owned façades: a WCF
SecurityService(via internalSecurityServiceClient, exposed throughSecurityGroupService/SystemUserProfile) and a REST Security API (viaSecurityApiClient). - 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-memoryTestRepository/TestUnitOfWorktest 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 aContainerBuilder.
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.*, generatedService References\*): encapsulates channel creation/disposal/error handling for legacy SOAP/WCF endpoints (DisposableClientBase<TChannel>, internalSecurityServiceClient, legacyDocumentServiceProxy/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:
ServiceRegistrationswires the above via Autofac (RegisterCoreServicesForWeb/RegisterCoreServicesForWindows), called by consuming application startup code outside this repository.
Interaction model¶
EnvironmentServiceBaseis the architectural hub: nearly every concrete service (SecurityServiceClient,SecurityApiClient,DbConnectionManager,DocumentService,PdfConvertAndMergeService,UserProfileService, and others) takes anIEnvironmentServicein its constructor and callsGetConfigSetting(...)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 directConfigurationManager.AppSettings[...]reads insideEnvironmentServiceBaseitself (ApplicationHost,EnvApiDeveloperSettingsOverride).MachineSecurityService→ADServiceis a private, in-process AD path used only to answer "is this machine a developer machine" (EnvironmentServiceBase.IsDeveloperMachine), separate from the WCF-frontedSecurityServiceClient/SecurityGroupServicepath and from the REST-frontedSecurityApiClientpath — three distinct, non-unified authorization mechanisms coexist behind different framework façades.- Authorization architecture is mixed: (a) a centralized WCF
SecurityServicefronted by internalSecurityServiceClientand exposed viaSecurityGroupService/SystemUserProfile; (b) a parallel REST Security API fronted bySecurityApiClient; (c) direct in-process AD lookups viaADService/MachineSecurityServicefor 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 resolvesIValidator<T>via an Autofac-backedValidatorFactoryand always additionally executes the"AuthorizationRules"FluentValidation rule set as a side effect of the defaultValidate<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) atInstancePerRequest(web) orInstancePerLifetimeScope(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<TEntity><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-memoryTestRepository/TestUnitOfWorktest double — so consumers or other Framework4 libraries must supply the real implementation; this library defines the contract only. - The
SAIF.Commonnamespace (EntityBase<TEntity>,IDataEntity,Enforce,LongSequence,Extensions.*) is referenced pervasively but has no confirmed<PackageReference>/<ProjectReference>in this project or its.nuspec— presumed transitive throughSAIF.HashUtilorSAIF.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 markedinternaland 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.HasAccesspath 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 WCFISecurityServicecontract is forwarded 1:1 bySecurityServiceClientbut has no caller within this library — only single-domainIsAuthorizedis exercised internally.*
Related documentation¶
- Index
- Overview
- Dependencies
- Configuration
- Operations and processes
- Business rules
- Security and authorization
- API reference
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.csprojCore\SAIF.Core\SAIF.Framework.Core.nuspecCore\SAIF.Core\app.configCore\SAIF.Core\Core\Services\ADService.csCore\SAIF.Core\Core\Services\MachineSecurityService.csCore\SAIF.Core\Core\Services\IEnvironmentService.csCore\SAIF.Core\Services.Common\EnvironmentServiceBase.csCore\SAIF.Core\Services.Common\DbConnectionManager.csCore\SAIF.Core\Services.Common\EnvironmentConfigKeys.csCore\SAIF.Core\Services.Common\WindowsEnvironmentService.csCore\SAIF.Core\Services.Common\WcfEnvironmentService.csCore\SAIF.Core\Services.Common\CustomEnvironmentService.csCore\SAIF.Core\Services.Common\WebEnvironmentService.csCore\SAIF.Core\Services.Common\SecureSettingCache.csCore\SAIF.Core\Services\ServiceRegistrations.csCore\SAIF.Core\Services\ServiceBase.csCore\SAIF.Core\Services\ValidatorFactory.csCore\SAIF.Core\Services\SecurityGroupService.csCore\SAIF.Core\Services\ClientProxies\SecurityServiceClient.csCore\SAIF.Core\Services\Utilities\SecurityApiClient.csCore\SAIF.Core\Services\Utilities\FluentValidationService.csCore\SAIF.Core\Services\Utilities\LogService.csCore\SAIF.Core\Services\Utilities\Documents\DocumentService.csCore\SAIF.Core\Services\Utilities\Documents\PdfConvertAndMergeService.csCore\SAIF.Core\Services\Utilities\Documents\FaxService.csCore\SAIF.Core\Services\Utilities\UserProfile\UserProfileService.csCore\SAIF.Core\Services\Utilities\UserProfile\ApplicationUserProfileBase.csCore\SAIF.Core\Services\Utilities\UserProfile\SystemUserProfile.csCore\SAIF.Core\Services.WCF\Contracts\ISecurityService.csCore\SAIF.Core\Services.WCF\ClientProxies\DisposableClientBase.csCore\SAIF.Core\Data\Interfaces\IUnitOfWork.csCore\SAIF.Core\Data\Interfaces\ISessionHelper.csCore\SAIF.Core\Data\Interfaces\Repositories\IRepository.csCore\SAIF.Core\Data\Interfaces\Repositories\IRepositoryFactory.csCore\SAIF.Core\Data\TestRepository\TestRepository.csCore\SAIF.Core\Data\TestRepository\TestUnitOfWork.csCore\SAIF.Core\Data\TestRepository\TestSessionHelper.csCore\SAIF.Core\Services\ClientProxies\Legacy\ActiveDirectoryServiceProxy.cs