---
title: Initialize environment client
summary: OP-01 operation detail page.
status: draft
owner: Framework.NCore maintainers
last_reviewed: 2026-10-02
library: SAIF.NetCore.EnvironmentClient
reference_type: package
---

# Initialize environment client

| Field | Value |
| --- | --- |
| Owner | `BaseEnvironmentClient..ctor` and `virtual Setup()` |
| Trigger | DI resolution of `IEnvironmentClient` (singleton via ServiceExtensions), or direct `new` |
| Inputs | `IConfiguration`, `IHostEnvironment.ApplicationName`, `IHttpJsonClient`, `IHostResolver`, `ISystemHashService`, and the OS environment variable `EnvironmentApiUrl` |
| Outputs | Populated `ApplicationName`, `ApplicationHost`, `TrackName`, `DeveloperSettingsOverrideFile`, `TimeToWaitSeconds = 60`, and a configured HTTP client |

## Steps
1. Initialize fields: `ApplicationName = IHostEnvironment.ApplicationName`; create empty `Settings` and `Sections`. The `ServiceUrl` field initializer reads `Environment.GetEnvironmentVariable("EnvironmentApiUrl")` ([BR-EC-01](../business-rules.md#br-ec-01-the-environment-api-base-url-must-be-present-at-construction)).
2. If `ServiceUrl` is null or empty, throw `MissingEnvironmentUrlVariableException` ([BR-EC-01](../business-rules.md#br-ec-01-the-environment-api-base-url-must-be-present-at-construction)). Construction fails.
3. Pre-check client setup: `HttpClient.SetClientInfo(ServiceUrl, "NetCore.EnvironmentClient", HostResolver.System.GetComputerName(), ApplicationName)`.
4. **Fetch tracks with retry** (`GetHostsByTrackWithResilience`). Read `EnvironmentClient:GetHostsByTrack:RetryCount` (default 3) and `:RetrySleepMs` (default 3000). Loop up to `RetryCount` times: `GET /v2/tracks/{ApplicationName}/value`. A call fails if it is not successful **or** returns an empty list ([BR-EC-02](../business-rules.md#br-ec-02-the-track%2Fhost-map-must-resolve-to-at-least-one-track)). On failure, append to the error log and `Thread.Sleep(attempt × RetrySleepMs)` (linear back-off: 3 s, 6 s, 9 s by default) ([BR-EC-03](../business-rules.md#br-ec-03-track-retrieval-is-retried-with-linear-back-off)). After all retries fail, throw `EnvironmentClientException` with the full error log.
5. **Resolve application host** (`ResolveApplicationHost`). Collect the distinct, lowercased, non-blank hosts from all tracks, then call `HostResolver.ResolveHost(hosts)` and set `ApplicationHost = HostResolver.Host` ([BR-EC-04](../business-rules.md#br-ec-04-a-config-file-host-override-requires-ad-override-permission-and-group-membership) through [BR-EC-07](../business-rules.md#br-ec-07-otherwise-the-host-defaults-to-the-machine-name)).
   - 5.1. The resolved host is determined by the standard `HostResolver` (the concrete `IHostResolver` implementation registered by the separate `SAIF.NetCore.ServiceExtensions` package's `RegisterEnvironmentClient`/`RegisterSecureEnvironmentClient`, not a registration owned by this library, and not necessarily the implementation present for any arbitrary injected `IHostResolver`) as follows. First, a permission check (`IsConfigOverrideAllowed`): read `AppSettings:EnvApiDeveloperOverrideAllowed`; if it is empty/missing, overrides are allowed by default; if it is present, `bool.TryParse` it — an explicit `"false"` **or** any malformed/non-boolean value both leave the parsed flag `false` (indistinguishable from each other), which skips the permission check entirely and denies the override. When the flag is `true`, the permission check opens a `PrincipalContext(ContextType.Domain)` and queries Active Directory for the current computer account and the `Developer_Machine_Users` group; this AD call is **not** wrapped in a try/catch anywhere in `HostResolver` — if the domain is unreachable or the lookup otherwise throws (for example a `PrincipalServerDownException`), that exception propagates uncaught through `ResolveHost`/`ResolveApplicationHost`, `Setup()`, and the constructor, rather than being translated into an `EnvironmentClientException`. If both AD lookups instead return (neither throws), and either returns `null` (including a missing/renamed group) or the computer is not a member, the permission check denies the override by returning `false` — this path alone does not throw. `AppConfigOverride` is a field initialized to `false` in the constructor and is only ever reassigned inside `TryResolveHostFromAppConfig`, which runs only when the permission check above returned `true`; when the permission check denies the override (or the override is skipped because the flag is already `false`), `TryResolveHostFromAppConfig` is never called and `AppConfigOverride` **retains whatever value it already held** — `false` on a fresh `HostResolver`, but an injected resolver whose public `Setup()` ran before with permission granted can already be `true`, and that prior value survives untouched; it is not reset to `false` by a later denied resolution — rather than being set based on the (unread) `AppSettings:ApplicationHost` value. Only when permission is granted is `AppSettings:ApplicationHost` read; a non-empty value there sets the host and `AppConfigOverride = true`. If permission was denied, or it was granted but the config value was empty, resolution falls back to matching a known track host against a segment of the application's content-root path; if that also finds no match, it falls back again to the local machine name (`DefaultedToMachineName = true`).
   - > **Origin**: Step 5.1 is implemented in [Resolve host](resolve-host.md) and executed on behalf of this operation.
6. **Resolve track** (`ResolveEnvironmentTrack`). For each track whose `Hosts` contains the resolved host (case-insensitive), set `TrackName = track.Name`. If several tracks match, the **last** one wins ([BR-EC-08](../business-rules.md#br-ec-08-the-resolved-host-must-belong-to-a-known-track)). If no track matches, throw `EnvironmentClientException("No environment track found for host! Host value: {ApplicationHost}")`.
7. **Developer settings override** (`ResolveDeveloperSettingsOverride`). Read `AppSettings:EnvApiDeveloperSettingsOverride`. If the file exists **and** `IsDeveloperMachine()` is true, set `DeveloperSettingsOverrideFile` ([BR-EC-09](../business-rules.md#br-ec-09-a-developer-override-file-is-honored-only-when-it-exists-and-the-machine-is-a-developer-machine)). Otherwise silently ignored.
8. Reconfigure the client for settings retrieval: `SetClientInfo(ServiceUrl, "NetCore.EnvironmentClient", ApplicationHost, ApplicationName)`. Set `TimeToWaitSeconds = 60` ([BR-EC-10](../business-rules.md#br-ec-10-environment-api-requests-identify-the-caller-by-host-and-application-name)).
9. (`SecureEnvironmentClient` only) Gate construction on `COREAPIENABLED == "1"` or `IsDeveloperMachine()` ([BR-EC-30](../business-rules.md#br-ec-30-secureenvironmentclient-construction-requires-server-enablement-or-a-developer-machine)); throws `EnvironmentClientException("This server is not enabled for CORE APIs.")` if neither is true. This runs **after** steps 1–8 have already made network calls.

No settings are loaded during setup; loading is lazy (see [Get setting value](get-setting-value.md)).

## Process flow

```mermaid
flowchart TD
    A["Ctor: read EnvironmentApiUrl"] --> B{ServiceUrl empty?}
    B -- Yes --> C[MissingEnvironmentUrlVariableException]
    B -- No --> D[SetClientInfo with machine name]
    D --> E[GetHostsByTrackWithResilience]
    E -->|all retries fail| F[EnvironmentClientException]
    E -->|success| G[ResolveApplicationHost via HostResolver]
    G --> H[ResolveEnvironmentTrack]
    H -->|no match| I["EnvironmentClientException: no track found"]
    H -->|match| J[ResolveDeveloperSettingsOverride]
    J --> K[SetClientInfo with ApplicationHost/ApplicationName]
    K --> L{SecureEnvironmentClient?}
    L -- Yes --> M{COREAPIENABLED=1 or developer machine?}
    M -- No --> N["EnvironmentClientException: not enabled for CORE APIs"]
    M -- Yes --> O[Client ready]
    L -- No --> O
```

## Sources
- `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs`
- `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SecureEnvironmentClient.cs`
- `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/ClientConfigs/GetHostsByTrackConfig.cs`
- `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/Exceptions/MissingEnvironmentUrlVariableException.cs`
- `src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/HostResolver.cs`
