SAIF.NetCore.DBConnectionClient architecture¶
SAIF.NetCore.DBConnectionClient is an implementation-layer library that provides ConnectionClient, a single behavioral type implementing the IDBConnectionClient contract from SAIF.NetCore.ServiceContracts; it does not connect to any database itself, but instead calls a remote HTTP service — the DBConnectionAPI — through an injected IHttpJsonClient and returns fully formatted SQL Server, PostgreSQL, or Oracle connection strings.
Responsibilities¶
- Implement
IDBConnectionClientand exposeGetSqlServerConnection,GetPostgreSqlServerConnection, andGetOracleConnectionfor callers that need a ready-to-use connection string. - Resolve the DBConnectionAPI base URL and the three endpoint path segments (
SqlConnectionEndpoint,PostgreSqlConnectionEndpoint,OracleConnectionEndpoint) from theDBConnectionClientconfiguration section viaIEnvironmentClient.GetSettingValue. - Configure the injected
IHttpJsonClientwith client identity headers (SetClientInfo) and, optionally, explicit NTLM service-account credentials (SetupClientCredentials). - Retrieve connection strings over HTTP with a bounded retry policy (
MaxRetrieveAttempts, fixed backoff delays) and cache successful results per connection name for the lifetime of the client instance. - Translate failures into
DBClientException, aSAIFException(ServiceContracts) subtype.
Component boundaries¶
ConnectionClient: non-sealed, template-method-style class that owns configuration resolution, HTTP client setup, retrieval-with-retry, and caching; every public operation and most extension points (Setup,RetrieveConnectionString,MaxRetrieveAttempts,RetrieveBackoffDelays,Delay) arevirtual/protected virtualso subclasses can override endpoints, retry policy, or wait behavior*.ConnectionClientKeys:public static classholding the configuration section name and the three endpoint-key constants consumed bySetup.DBClientException: thin exception type that wraps failures as aSAIFException(ServiceContracts).IHttpJsonClient/IHttpRequestResult/IEnvironmentClient(ServiceContracts interfaces): consumed, not implemented, by this library; concrete behavior is supplied by whatever the host application registers (in the standard stack,SAIF.NetCore.HttpClientsandSAIF.NetCore.EnvironmentClientrespectively)*.
Interaction model¶
- A consuming application (typically via
SAIF.NetCore.ServiceExtensions) constructsConnectionClientwith anIHttpJsonClientand anIEnvironmentClient; the constructor itself callsSetup()to resolve the service URL, endpoint segments, and client-identity headers before the constructor returns. The consumer separately callsSetupClientCredentials(username, password)after construction to switch from ambient NTLM identity to explicit service-account credentials. - Callers then invoke
GetSqlServerConnection,GetPostgreSqlServerConnection, orGetOracleConnection, each of which builds a database-specific cache key and URL path and delegates to the shared cached-lookup logic. - The cached lookup acquires an instance-wide lock, checks the in-memory cache keyed by connection name, and returns immediately on a cache hit. On a cache miss it calls
RetrieveConnectionString, which issuesHttpClient.GetAsync(urlPath)throughIHttpJsonClientand classifies the per-attemptIHttpRequestResultread from the completed task (deliberately avoiding the sharedIHttpJsonClient.RequestResultproperty to prevent a cross-call race*): a successful, non-empty response returns immediately; HTTP 401/403/404 fail fast with no retry at this (outer) level; a 503 or network-level error is transient and retries up toMaxRetrieveAttempts(4) times with fixed backoff delays (2s, 3s, 5s); any other non-success or an empty body fails immediately. Each single outerGetAsynccall is not necessarily a single HTTP request: when the standardHttpJsonClientimplementation is registered, that call applies its own independent inner retry policy (default on 401/502/503, up to 4 attempts with a 1-second delay) before returning a result to this outer step, so the outer and inner retry/backoff schedules are separate and additive, not the same policy described twice. - On success the connection string is decoded, cached, and returned; on a permanent failure or exhaustion of transient retries the failure is surfaced as a
DBClientException.
Architecture diagram¶
The following diagram shows how ConnectionClient sits between a consuming application and the remote DBConnectionAPI, mediated by the ServiceContracts interfaces it depends on.
flowchart TD
APP["Consuming application<br>(via SAIF.NetCore.ServiceExtensions)"] -->|constructs + calls| CC["ConnectionClient<br>(SAIF.NetCore.DBConnectionClient)"]
CC -->|IEnvironmentClient.GetSettingValue| ENV["IEnvironmentClient<br>(ServiceContracts contract)"]
CC -->|SetClientInfo / SetNtlmAuthentication / GetAsync| HTTP["IHttpJsonClient<br>(ServiceContracts contract)"]
HTTP -->|GET connection-string endpoints| API["DBConnectionAPI<br>(external HTTP service)"]
CC -->|wraps failures as| EX["DBClientException<br>(extends SAIFException)"]
Sequence diagram¶
The following diagram shows the primary request/response sequence for retrieving a SQL Server connection string, including both ConnectionClient's own outer retry loop and the standard IHttpJsonClient implementation's separate, independent inner retry policy that it wraps.
sequenceDiagram
participant Consumer
participant ConnectionClient
participant IHttpJsonClient
participant DBConnectionAPI
Consumer->>ConnectionClient: GetSqlServerConnection(server, instance, userName)
ConnectionClient->>ConnectionClient: Acquire lock, check in-memory cache
alt cache hit
ConnectionClient-->>Consumer: cached connection string
else cache miss
loop outer: up to MaxRetrieveAttempts (4)
ConnectionClient->>IHttpJsonClient: GetAsync("/{SqlEndpoint}/{server}/{instance}/{userName}")
loop inner (standard HttpJsonClient only): up to 4 HTTP requests
IHttpJsonClient->>DBConnectionAPI: GET connection-string endpoint
DBConnectionAPI-->>IHttpJsonClient: HTTP response
Note over IHttpJsonClient: Retries on 401/502/503<br>(default RetryOnStatusCodes), 1s delay
end
IHttpJsonClient-->>ConnectionClient: IHttpRequestResult (converted from the final inner HTTP response)
break success, non-empty body
ConnectionClient-->>Consumer: decode and cache, return connection string
end
break 401/403/404 (permanent at the outer level)
ConnectionClient-->>Consumer: throw DBClientException (no outer retry)
end
alt 503 or network error (transient) and attempts remain
ConnectionClient->>ConnectionClient: Delay(outer backoff) and retry
else other non-success, empty body, or transient retries exhausted
break terminal failure
ConnectionClient-->>Consumer: throw DBClientException
end
end
end
end
Design constraints¶
- No project references between libraries in this repository; the only cross-library dependency is the
SAIF.NetCore.ServiceContractsNuGet package, consistent with the repository-wide layering inArchitecture.md. - The library ships no
IServiceCollectionextension of its own; DI wiring, singleton lifetime, and credential retrieval are composed externally bySAIF.NetCore.ServiceExtensions*. IHttpJsonClientis documented as intended for transient use, but a singletonConnectionClientcaptures a single instance for the process lifetime, which is a potential lifetime mismatch combined with stored NTLM credential state*.- Actual values for the service URL and the three endpoint path segments are environment configuration, not present in this repository**.
Related documentation¶
- Index
- Overview
- Dependencies
- Configuration
- Operations and processes
- Business rules
- Security and authorization
- API reference
- SAIF.NetCore.ServiceContracts overview
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¶
src/SAIF.NetCore.DbConnectionClient/SAIF.NetCore.DBConnectionClient/SAIF.NetCore.DBConnectionClient/ConnectionClient.cssrc/SAIF.NetCore.DbConnectionClient/SAIF.NetCore.DBConnectionClient/SAIF.NetCore.DBConnectionClient/ClientException.cssrc/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/IDBConnectionClient.cs,IHttpJsonClient.cs,IHttpRequestResult.cs,IEnvironmentClient.cs,SAIFException.cs,HttpClientOptions.cssrc/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/HttpJsonClient/HttpJsonClient.cs(inner retry policy detail reached when the standardIHttpJsonClientimplementation is registered)src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IServiceCollectionExtensions.csArchitecture.md