---
title: SAIF.NetCore.Clients.UC4 architecture
summary: Architectural responsibilities, boundaries, and interaction patterns.
status: draft
owner: SAIF Framework Platform Team
last_reviewed: 2026-10-02
library: SAIF.NetCore.Clients.UC4
reference_type: package
---

# SAIF.NetCore.Clients.UC4 architecture

SAIF.NetCore.Clients.UC4 is an implementation-layer library (per `Architecture.md`) that provides a single, thin outbound REST client for scheduling jobs against the UC4/Automic job-scheduling system's "UC4 Core API," wrapping `IHttpJsonClient` and `IEnvironmentClient` from `SAIF.NetCore.ServiceContracts` with no other SAIF package dependency.

## Responsibilities
- Validate at construction time that the two required `uc4coreapi` environment settings (`url`, `schedulejobroute`) exist.
- Lazily configure the injected `IHttpJsonClient` with the UC4 Core API base URL and caller-identity headers on the first `ScheduleJob` call.
- Issue a single outbound POST to the UC4 Core API's schedule-job route, appending the caller-supplied job name to the configured route.
- Return the raw `IHttpRequestResult` to the caller unchanged, leaving success/failure interpretation and response parsing to the consumer.

## Component boundaries
- `IUC4Client` (namespace `SAIF.NetCore.Clients.UC4`): the public contract, exposing only `ScheduleJob(string appname, string jobname)`.
- `UC4Client` (namespace `SAIF.NetCore.Clients.UC4.Services`): the sole implementation, owning settings validation, lazy client initialization (`Init`), and the outbound POST.
- `Constants` (internal): owns the `uc4coreapi` setting-group and key names (`url`, `schedulejobroute`).
- The library has no DI registration extension method; consumers register `IUC4Client`/`UC4Client` by hand, and no other library in this repository registers it on their behalf*.

## Interaction model
- A consumer constructs `UC4Client` (directly, or via manual DI registration) supplying `IEnvironmentClient` and `IHttpJsonClient`; the constructor eagerly validates the two `uc4coreapi` settings exist and reads their values, throwing `NotSupportedException` if either key is missing.
- On the first `ScheduleJob` call, `UC4Client.Init` configures the injected `IHttpJsonClient` with the base URL and identity headers (`Client-User`, `Client-Name`, `Application-ID`); this configuration is fixed for the lifetime of the `UC4Client` instance and is not re-applied on later calls, even with a different `appname`*.
- Each `ScheduleJob` call POSTs an empty JSON object (`{}`), with no job parameters, to `{ScheduleJobEndpoint}{jobname}` through `IHttpJsonClient`, which applies its own default retry policy (401/502/503, up to 3 retries) before returning the result.
- `IEnvironmentClient` and `IHttpJsonClient` are resolved from the DI container by the consumer; this library has no compile-time dependency on their concrete implementations (`SAIF.NetCore.EnvironmentClient`, `SAIF.NetCore.HttpClients`), which the consumer typically obtains via `SAIF.NetCore.ServiceExtensions`*.

## Architecture diagram
The following diagram shows this library's single NuGet dependency on `SAIF.NetCore.ServiceContracts`, the runtime services a consumer must supply, and the outbound call to the external UC4 Core API.

```mermaid
flowchart TD
    SC["SAIF.NetCore.ServiceContracts<br>(IEnvironmentClient, IHttpJsonClient,<br>IHttpRequestResult)"]
    UC4["SAIF.NetCore.Clients.UC4<br>IUC4Client / UC4Client"]
    ENV["SAIF.NetCore.EnvironmentClient<br>(IEnvironmentClient impl)"]
    HTTP["SAIF.NetCore.HttpClients<br>(IHttpJsonClient impl)"]
    UC4API["UC4 Core API<br>(external job scheduler)"]
    APP["Consuming application"]

    UC4 -.->|NuGet ref| SC
    APP -->|constructs / resolves| UC4
    UC4 -->|DI-resolved by consumer| ENV
    UC4 -->|DI-resolved by consumer| HTTP
    UC4 -->|POST schedule-job route| UC4API
```

## Sequence diagram
The following diagram shows the primary request sequence for scheduling a UC4 job, including the first-call lazy initialization.

```mermaid
sequenceDiagram
    participant App as Consuming application
    participant UC4Client
    participant EnvironmentClient as "IEnvironmentClient"
    participant HttpJsonClient as "IHttpJsonClient"
    participant UC4API as "UC4 Core API"

    App->>UC4Client: new UC4Client(env, httpJsonClient)
    UC4Client->>EnvironmentClient: HasSetting / GetSettingValue(uc4coreapi.url, schedulejobroute)
    EnvironmentClient-->>UC4Client: ServiceUrl, ScheduleJobEndpoint
    App->>UC4Client: ScheduleJob(appname, jobname)
    alt first call (IsConfigured == false)
        UC4Client->>HttpJsonClient: SetClientInfo(ServiceUrl, ClientName, MachineName, appname)
    end
    UC4Client->>HttpJsonClient: PostAsync(ScheduleJobEndpoint + jobname, {})
    HttpJsonClient->>UC4API: POST schedule-job route
    UC4API-->>HttpJsonClient: HTTP response
    HttpJsonClient-->>UC4Client: IHttpRequestResult
    UC4Client-->>App: IHttpRequestResult
```

## Design constraints
- The library takes **no NuGet dependency on any other SAIF implementation library** — only on `SAIF.NetCore.ServiceContracts` — consistent with the repo-wide rule that implementation libraries depend solely on the foundation layer.
- `IsConfigured` has a public setter; a caller that sets it `true` before the first `ScheduleJob` call skips `Init` entirely, which fails later with `ClientNotInitializedException` from `HttpJsonClient` unless the injected client was configured elsewhere*.
- Client identity (`appname`) is fixed from the first successful call for the life of the instance; later calls with a different `appname` silently reuse the first value ([BR-UC4-06](business-rules.md#br-uc4-06-client-identity-is-fixed-on-first-use)).
- The schedule-job POST is retried automatically by `HttpJsonClient` on 401/502/503 — standard `HttpJsonClient` defaults, changeable by a host that calls `SetOptions`, though UC4 itself never calls `SetOptions`; whether a retry after an already-accepted job can result in duplicate job submissions depends on whether the UC4 Core API's schedule endpoint is idempotent, which is unknown**.
- UC4 itself calls no authentication method (no NTLM, Basic, or bearer token) and does not clear or override the injected `IHttpJsonClient`'s authenticator; `HttpJsonClient.CreateClient` assigns `client.Authenticator = _authenticator`, preserving whatever authenticator the host configured on that instance — `null` if the host configured none, or a working authenticator (demonstrably capable of carrying credentials) if it did. Only informational, caller-asserted headers (`Client-Name`, `Application-ID`, `Client-User`) are added by UC4 itself.
- There is no DI registration extension method shipped with this library; registration is entirely manual for every consumer.

## Related documentation
- [Index](index.md)
- [Overview](overview.md)
- [Dependencies](dependencies.md)
- [Configuration](configuration.md)
- [Operations and processes](operations-processes.md)
- [Business rules](business-rules.md)
- [API reference](api/index.md)

> **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.Clients.UC4/SAIF.NetCore.Clients.UC4/SAIF.NetCore.Clients.UC4/SAIF.NetCore.Clients.UC4.csproj`
- `src/SAIF.NetCore.Clients.UC4/SAIF.NetCore.Clients.UC4/SAIF.NetCore.Clients.UC4/Constants.cs`
- `src/SAIF.NetCore.Clients.UC4/SAIF.NetCore.Clients.UC4/SAIF.NetCore.Clients.UC4/IUC4Client.cs`
- `src/SAIF.NetCore.Clients.UC4/SAIF.NetCore.Clients.UC4/SAIF.NetCore.Clients.UC4/Services/UC4Client.cs`
- `src/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/HttpJsonClient/HttpJsonClient.cs` — declares the retry policy and `CreateClient`'s `client.Authenticator = _authenticator` assignment described in Design constraints.
- `src/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/HttpClientOptions.cs` — declares the default `RetryOnStatusCodes` set.
- Architecture.md
