Register DB connection client¶
This operation registers a lazily-constructed IDBConnectionClient and, on first resolution, bootstraps its credentials from a secure environment setting hashed against the DBConnectionClient assembly (not the consuming application's assembly).
| Field | Value |
|---|---|
| Operation ID | OP-03 |
| Trigger | Application startup code calls RegisterDBConnectionClient(); execution of steps 2–5 happens lazily on first IDBConnectionClient resolution. |
| Inputs | None (parameterless); relies on a previously registered IHttpJsonClient and IEnvironmentClient. |
| Outputs | A configured IDBConnectionClient singleton with DB-service credentials applied. |
| Primary components | IServiceCollectionExtensions.RegisterDBConnectionClient |
| Entry point | src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IServiceCollectionExtensions.cs (L62–75) |
Steps¶
- Register a Singleton
IDBConnectionClientfactory (BR-SE-04) - Executed lazily: the factory body runs only on first resolve.
new ConnectionClient(GetRequiredService<IHttpJsonClient>(), GetRequiredService<IEnvironmentClient>()), whose constructor immediately calls its ownSetup(): reads the fourDBConnectionClientsettings (ServiceUrl,SqlConnectionEndpoint,PostgreSqlConnectionEndpoint,OracleConnectionEndpoint) from theDBConnectionClientconfiguration section viaIEnvironmentClient.GetSettingValue, callsHttpClient.SetClientInfo(ServiceUrl, "DBConnectionClient", EnvClient.ApplicationHost, EnvClient.ApplicationName)to set the client's identity/base URL, then callsHttpClient.SetNtlmAuthentication()with no credentials — this is the default/current process-identity NTLM context (theHttpJsonClientimplementation's zero-argument overload), not an anonymous/unauthenticated mode.
Origin:
ConnectionClient's construction and connection-string resolution logic is implemented inConstruct and configure client(SAIF.NetCore.DBConnectionClient); the constructor/Setup()work summarized above runs synchronously as part of this factory, on first resolution ofIDBConnectionClient. 3.new SystemHashService(typeof(ConnectionClient).Assembly).Get(SystemType.WebApp)—Getresolves the DBConnectionClient assembly (passed into the constructor, soGetAssembly()returns it directly rather than falling back toAssembly.GetCallingAssembly()) and callsComputeHash(SystemType.WebApp, "SAIF.NetCore.DBConnectionClient"), the salted path (viaSaltShaker(DateTime.Now).SaltHash), not the unsaltedComputeHashNow; the hash is keyed on the DBConnectionClient assembly, not the consuming application's assembly (BR-SE-04) -ComputeHashruns two sub-phases: (1) build the identity string"{systemName}-{(int)SystemType.WebApp}", encode it as UTF-16LE bytes, compute its SHA-256 digest, and Base64-encode the digest (44 characters) — the deterministic identity hash; (2) construct aSaltShaker(DateTime.Now)that hex-encodes the current minute/year/day/millisecond/second/hour/month, thenSaltHashinserts each encoded date part at a pseudo-random position in the identity hash and prepends a 42-character location map recording where each part landed — so the returned credential embeds a recoverable timestamp without being a stable, cacheable value.Origin: The full step-by-step identity-hash and salting detail summarized above is implemented in
Compute salted system hash(SAIF.NetCore.SystemHash); this step supplies the DBConnectionClient assembly as the hash identity andSystemType.WebAppfromSAIF.NetCore.ServiceContracts. 4.env.GetSecureSetting("connectionservicecreds", "dbconnectionclient", hash)(BR-SE-04), BR-SE-01 - On a secureIEnvironmentClient(SecureEnvironmentClient): callsCheckForUpdates()directly first (not throughLoadSection/LoadSectionAsync). This check has three possible outcomes, not a single "refresh if empty or elapsed" rule: an empty settings cache reloads the entire cache immediately with no network call; a non-empty cache before the 60-second throttle window issues no call and does not reload; a non-empty cache at or past that window issues aGET /settings/lastRefreshedprobe and reloads only if that call succeeds and the server's timestamp is newer — see Refresh check and cache reload (SAIF.NetCore.EnvironmentClient) for the full branch detail. It then checks a localSecureSettingCachekeyed on"{section}.{configKey}"; on a cache miss, it builds the secure-setting URL and (ifHasSettingreports the key exists) issues a synchronousHttpClient.Get(urlPath)against the remote Environment API, then parses the response into the requested type. If the retrieved/cached value isnull/default, it throwsEnvironmentClientException("No crypto data found for requested secure setting: " + configKey). - On failure: a non-secureIEnvironmentClientregistration (see Register environment client) throwsEnvironmentClientExceptionimmediately, without attempting a remote call.Origin: The cache/remote-call/error logic summarized above is implemented in
Get secure setting(SAIF.NetCore.EnvironmentClient); this operation's factory invokes it directly (not merely registering it) the first timeIDBConnectionClientis resolved. 5.creds.Split("|")→SetupClientCredentials(credentials[0], credentials[1]), which callsHttpClient.SetNtlmAuthentication(username, password)to replace the default/current-process-identity NTLM configured duringSetup()with the retrieved service-account credentials (BR-SE-05) - On failure: no length check is performed, so a malformed value with fewer than two|-separated parts throwsIndexOutOfRangeException.Origin: Credential application is implemented in
Apply service account credentials(SAIF.NetCore.DBConnectionClient); theSetNtlmAuthentication(username, password)call summarized above runs synchronously as part of this factory, on first resolution ofIDBConnectionClient.
Process flow¶
This diagram shows the full lazy-construction sequence that runs once, on first IDBConnectionClient resolution — it is not re-run on subsequent resolutions of the singleton.
flowchart TD
Start([First IDBConnectionClient resolve]) --> S1[Construct ConnectionClient]
S1 --> S2[Compute hash on DBConnectionClient assembly]
S2 --> S3{Environment client is secure?}
S3 -->|No| EndErr1([EnvironmentClientException])
S3 -->|Yes| S4[GetSecureSetting connectionservicecreds]
S4 --> S5{Value has 2+ parts split on pipe?}
S5 -->|No| EndErr2([IndexOutOfRangeException])
S5 -->|Yes| S6[SetupClientCredentials]
S6 --> EndOk([DB connection client ready])
Failure and edge-case behavior¶
- Non-secure environment client registration →
EnvironmentClientExceptionon credential fetch. - Malformed credential value (no
|or only one part) →IndexOutOfRangeException.
Related documentation¶
Sources¶
src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IServiceCollectionExtensions.cs