---
title: Construct and configure the client
summary: Build a working ConnectionClient instance bound to the DBConnectionAPI.
status: draft
owner: Framework.NCore maintainers
last_reviewed: 2026-10-02
library: SAIF.NetCore.DBConnectionClient
reference_type: package
operation_id: OP-DBC-01
trigger: DI factory in ServiceExtensions.RegisterDBConnectionClient (singleton), or direct new
---

# Construct and configure the client

This operation builds a `ConnectionClient` instance, caches its two injected dependencies, and resolves the DBConnectionAPI service URL, the three engine endpoint segments, and the outbound client-identity headers before the instance is handed to a caller.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-DBC-01 |
| **Trigger** | DI factory in `ServiceExtensions.RegisterDBConnectionClient` (singleton lifetime), or a direct `new ConnectionClient(IHttpJsonClient httpJsonClient, IEnvironmentClient envClient)` call |
| **Inputs** | `IHttpJsonClient httpJsonClient`, `IEnvironmentClient envClient` |
| **Outputs** | A configured `ConnectionClient` instance |
| **Primary components** | `ConnectionClient` constructor, `ConnectionClient.Setup` |
| **Entry point** | `src/SAIF.NetCore.DbConnectionClient/SAIF.NetCore.DBConnectionClient/SAIF.NetCore.DBConnectionClient/ConnectionClient.cs` |

## Steps

1. Initialize the empty connection cache `_connections` and store the two injected dependencies (`IHttpJsonClient`, `IEnvironmentClient`).
2. Call the `virtual` `Setup()` method.
3. Read `ServiceUrl` from configuration key `DBConnectionClient:ServiceUrl` via the injected `IEnvironmentClient.GetSettingValue(key, section)` contract ([BR-DBC-01](../business-rules.md#br-dbc-01-configuration-keys-source-the-service-url-and-endpoint-segments)).
   - 3.1. Build a dictionary key from `section`/`configKey` and load the `DBConnectionClient` section into the settings cache if it has not already been loaded. When the standard `BaseEnvironmentClient` implementation is registered, loading a section first calls `CheckForUpdates`, which reloads the whole settings cache only when a periodic timestamp probe (throttled to once per `TimeToWaitSeconds`, 60 seconds by default) determines the remote EnvironmentAPI's `LastRefreshed` is newer than the local value, or unconditionally when the local cache is still empty — it is not an unconditional reload on every call once the standard refresh interval has elapsed. That reload clears the cached settings dictionary but preserves the set of already-loaded section names, then reloads each of them in turn; an exception partway through that per-section reload loop can leave a not-yet-reloaded section still marked loaded with no data behind it until a later refresh succeeds.
   - 3.2. If the `DBConnectionClient` section is not yet loaded, the standard implementation issues one request to the EnvironmentAPI for it and classifies the result: a null result, an unsuccessful response, or a successful response with no settings collection at all throws `EnvironmentClientException`, which propagates out of this operation uncaught; a successful response with zero individual settings is not an error, but it stores nothing and leaves the section unmarked (or removes it if it had previously been marked loaded), so the next call retries the load; only a successful, nonempty result both upserts the returned settings into the cache and marks the section name as loaded.
   - 3.3. Look the key up in the loaded settings and return its value, or an empty string if the key is not found. For the standard `BaseEnvironmentClient` implementation, a configured developer-settings-override file is checked first and takes precedence over the loaded dictionary; falling through to the dictionary and then to an empty string on a miss means that implementation does not throw for a missing key — this is a property of that registered implementation, not a universal guarantee of the `IEnvironmentClient` contract itself.

   > **Origin**: Steps 3.1–3.3 are implemented in [Load section](../../saif-netcore-environmentclient/operations/load-section.md) and [Get setting value](../../saif-netcore-environmentclient/operations/get-setting-value.md) (`SAIF.NetCore.EnvironmentClient`, `BaseEnvironmentClient.CheckForUpdates`/`LoadSection`/`HandleGetConfigurationSettingsResults`/`GetSettingFromDictionary`) when the host registers the standard `BaseEnvironmentClient`/`SecureEnvironmentClient` implementation, and executed on behalf of this operation. A differently registered `IEnvironmentClient` implementation can resolve the value differently.
4. Read `SqlConnectionEndpoint`, `PostgreSqlConnectionEndpoint`, and `OracleConnectionEndpoint` from the same `DBConnectionClient` section ([BR-DBC-01](../business-rules.md#br-dbc-01-configuration-keys-source-the-service-url-and-endpoint-segments)).
   - No null/empty validation is performed — missing values flow unchecked into URL paths built later.
5. Configure the HTTP client's identity: `SetClientInfo(ServiceUrl, "DBConnectionClient", EnvClient.ApplicationHost, EnvClient.ApplicationName)`, which sets the base URL plus `Client-User`, `Client-Name`, and `Application-Id` headers ([BR-DBC-02](../business-rules.md#br-dbc-02-every-request-identifies-itself-via-client-info-headers)).
   - 5.1. This library (`ConnectionClient.Setup`) itself constructs neither a `Uri` nor a `ClientInfo`; it only calls `IHttpJsonClient.SetClientInfo` with the four string arguments. When the standard `HttpJsonClient` implementation is registered, that call first constructs and assigns a new `ClientInfo` from the three identity arguments — throwing immediately on a null identity argument — and only after that succeeds constructs and assigns a new `Uri` from `ServiceUrl`, throwing immediately on an invalid `ServiceUrl`; the two assignments are not atomic, so a failing `ServiceUrl` can still leave the newly constructed `ClientInfo` applied to the instance.

   > **Origin**: Step 5.1 is implemented in [Initialize client](../../saif-netcore-httpclients/operations/initialize-client.md) (`SAIF.NetCore.HttpClients`) when the standard `HttpJsonClient` implementation is registered, and executed on behalf of this operation.
6. Enable NTLM authentication using the current process identity: `SetNtlmAuthentication()` with no arguments ([BR-DBC-03](../business-rules.md#br-dbc-03-ntlm-authentication%2C-defaulting-to-process-identity)).
   - 6.1. This library calls only `IHttpJsonClient.SetNtlmAuthentication()` with no arguments; when the standard `HttpJsonClient` implementation is registered, that call builds a parameterless `NtlmAuthenticator` (current process identity) and stores it on the client instance as `_authenticator`. The stored authenticator is only assigned to a `RestClient` later, inside `CreateClient`, each time that implementation builds a new `RestClient` for an outbound request — not at the time `SetNtlmAuthentication` is called. A differently registered `IHttpJsonClient` implementation is not required to construct an `NtlmAuthenticator` or assign it the same way.

   > **Origin**: Step 6.1 is implemented in [Configure authentication](../../saif-netcore-httpclients/operations/configure-authentication.md) (`SAIF.NetCore.HttpClients`) when the standard `HttpJsonClient` implementation is registered, and executed on behalf of this operation.
   - On failure: any exception raised by the environment client or HTTP client during steps 3–6 propagates out of the constructor uncaught; there is no error handling in `Setup`.

## Process flow

```mermaid
flowchart TD
	Start([Constructor invoked]) --> Init[Initialize cache and store dependencies]
	Init --> Setup[Call Setup]
	Setup --> ReadUrl["Read ServiceUrl, endpoint segments"]
	ReadUrl --> ClientInfo["SetClientInfo: base URL + identity headers"]
	ClientInfo --> Ntlm["SetNtlmAuthentication: current process identity"]
	Ntlm --> Done([Configured instance ready])
```

## Failure and edge-case behavior
- Any exception thrown by `IEnvironmentClient` or `IHttpJsonClient` during `Setup()` propagates out of the constructor; the caller receives a failed construction, not a partially configured instance.
- Because `Setup()` is `virtual` and called from the constructor, a subclass override runs before the subclass's own constructor body completes*.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming
> conventions, or contextual evidence where direct confirmation was not available
> in source artifacts.

## Sources
- `src/SAIF.NetCore.DbConnectionClient/SAIF.NetCore.DBConnectionClient/SAIF.NetCore.DBConnectionClient/ConnectionClient.cs`
- `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs` (`CheckForUpdates`, `LoadSection`, `HandleGetConfigurationSettingsResults`, `GetSettingFromDictionary` — collaborator detail reached when the standard `IEnvironmentClient` implementation is registered)
- `src/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/HttpJsonClient/HttpJsonClient.cs` (`SetClientInfo`, `SetNtlmAuthentication`, `CreateClient` — collaborator detail reached when the standard `IHttpJsonClient` implementation is registered)
