Skip to content

Example: ASP.NET Core API configuration

configuration.md documents how an ASP.NET Core API is configured across environments: the appsettings*.json bootstrap values, the settings it reads from the Environment API through IEnvironmentClient, options binding, the database connections it composes at run time, and the IIS web.config surface. Doc gen produces one per API at docs/apis/<api-slug>/configuration.md.

What reviewers should check

  • There is no connection-strings table. A service of this kind carries no ConnectionStrings section; its connections are resolved at run time from an Environment API setting and a pool code, and the page documents that resolution instead.
  • The pool code is never labelled "schema". It is a SAIF identifier forwarded to a connect-info service, and the Oracle schema is resolved server-side.
  • No secret, credential, host or address is reproduced anywhere: not from appsettings.json, not from settings.yml, not from web.config, not from the .http or env/.env* files. Secure settings record the hash source and never a value.
  • A key is in the Environment API settings catalog because a GetSettingValue or GetSecureSetting<T> call names it in source, and each row names the consuming class. A key that appears only in environmentsettings/settings.yml is at most a stale-manifest note, never a catalog row.
  • The Environment variance table is pipeline-seeded evidence only, cites environmentsettings/settings.yml, and characterizes the shape of the variance rather than the values.
  • Commented-out lines in appsettings.json are recorded as a note on the active key, not as an active value or as a deployment track.
  • Hosting configuration records stale values as findings, for example a web.config arguments target framework that no longer matches the project, and notes that launchSettings.json is local development only.
  • Behavior contributed by CoreAPIStartup or other SAIF packages carries the dagger, and the page carries the canonical note box that explains it.

Example

The document below is a complete, correct api-configuration.md for a fictional ASP.NET Core API.

View rendered example — the same document as a real page, so you can compare rendering as well as source.

---
title: Configuration
summary: appsettings, Environment API settings, options binding, runtime-resolved database connections, and the IIS web.config surface.
status: draft
owner: Premium Systems Team
last_reviewed: 2026-10-21
---

# Configuration

`SAIF.Premium.Api` is configured from three places: a small `appsettings.json`
that bootstraps the host, the Environment API that supplies every
environment-specific value, and two bound options types that carry the rating
limits. The service has three Environment API keys, one of them secure, and one
runtime-resolved Oracle connection. Rating limits live in `appsettings.json`
and are the only business-relevant values a deployer can change without the
Environment API.

Local configuration is limited to `appsettings*.json` bootstrap values read through the ASP.NET Core configuration system; environment-specific values are retrieved at runtime from the Environment API through `IEnvironmentClient`. Database connections are **not** declared in configuration: this repository carries no `ConnectionStrings` section, and each connection is composed at run time from an Environment API setting and a pool code passed to `IDBConnectionClient`. That pool code is a SAIF-specific identifier forwarded to a connect-info service - it is **not the Oracle schema**, which is resolved server-side and is not visible from source.†

## appsettings files

| File | Key | Value | Read by | Purpose |
| --- | --- | --- | --- | --- |
| `appsettings.json` | `AppSettings:ApplicationHost` | `entdev6` (an alternative value, `enttest01`, is commented out) | `IEnvironmentClient` (`SAIF.NetCore.ServiceExtensions`); `Startup` reads it into `EnvironmentName` at `src/SAIF.Premium.Api/Startup.cs:23` | Environment API host resolution† |
| `appsettings.json` | `AppSettings:ApplicationName` | `SAIF.Premium.Api` | `IEnvironmentClient` (`SAIF.NetCore.ServiceExtensions`) | Application identity for Environment API lookups† |
| `appsettings.json` | `AppSettings:BatchPageSize` | `500` | `IConfiguration["AppSettings:BatchPageSize"]` in `BatchRecalculationService` | Policies loaded per page by the batch recalculation |
| `appsettings.json` | `PremiumRating:MinimumPremium` | `250.00` | `IOptionsMonitor<PremiumRatingOptions>` in `RatingEngine` | Policy minimum premium applied by the rating engine |
| `appsettings.json` | `PremiumRating:MaxAdjustmentPercent` | `25` | `IOptionsMonitor<PremiumRatingOptions>` in `RatingEngine` | Largest adjustment, as a percentage of the base premium |
| `appsettings.json` | `Logging:LogLevel:Default` | `Information` | ASP.NET Core logging | Log filtering |
| `appsettings.json` | `Logging:LogLevel:Microsoft.AspNetCore` | `Warning` | ASP.NET Core logging | Log filtering for framework categories |
| `appsettings.json` | `AllowedHosts` | `*` | Host filtering middleware | Allowed host headers |
| `appsettings.Development.json` | `Logging:LogLevel:Default` | `Debug` | ASP.NET Core logging | Verbose logging for local development |

No `ConnectionStrings` section exists in either file. `AppSettings:ApplicationHost`
names a single Environment API host for the whole service; the commented-out
`enttest01` line is a local-run alternative, not a deployment track.

## Environment API settings

| Key | Group | Retrieved by | Consuming class | Secure | Varies by environment | Purpose |
| --- | --- | --- | --- | --- | --- | --- |
| `oracledatabase` | - | `GetSettingValue` | `ConfigureUnitOfWorkOptions` | No | Yes | Database identifier passed to `IDBConnectionClient` |
| `ratetablecacheminutes` | `PremiumApi` | `GetSettingValue<int>` | `RateTableCache` | No | Yes | Minutes a loaded rate table is kept in memory |
| `batchsigningkey` | `PremiumApi` | `GetSecureSetting<string>` | `BatchRequestSigner` | Yes | Yes | Key used to sign recalculation batch requests; hash source `ISystemHashService.Get(SystemType.WebApp)` |

## Options binding

| Options type | Bound by | Source of values | Consumed by | Source |
| --- | --- | --- | --- | --- |
| `UnitOfWorkOptions` | `ConfigureOptions<ConfigureUnitOfWorkOptions>` | `IDBConnectionClient` (see below) | `IUnitOfWork` created by `AddNhibernateServices<Startup>()` | `src/SAIF.Premium.Api/Startup.cs:38` |
| `PremiumRatingOptions` | `Configure<PremiumRatingOptions>(Configuration.GetSection("PremiumRating"))` | `appsettings.json` `PremiumRating` | `IOptionsMonitor<PremiumRatingOptions>` in `RatingEngine` | `src/SAIF.Premium.Api/Startup.cs:39` |

Options registered inside `CoreAPIStartup` (authentication, authorization and
the Environment API client) are opaque and are not listed.†

## Runtime-resolved database connections

| Connection | Resolution call | Environment setting | Pool code | Resolved in | Consumed by |
| --- | --- | --- | --- | --- | --- |
| Premium database | `IDBConnectionClient.GetOracleConnection(IEnvironmentClient.GetSettingValue("oracledatabase"), "PREM01")` | `oracledatabase` | `PREM01` | `src/SAIF.Premium.Api/Configuration/ConfigureUnitOfWorkOptions.cs:21` | `AddNhibernateServices<Startup>()` |

The connection is resolved per scope: `ConfigureUnitOfWorkOptions` runs when the
options are built for a request, and `UnitOfWork` reads them through
`IOptionsSnapshot<UnitOfWorkOptions>`, so a change to the Environment API value
reaches the next request without a restart. When resolution fails, the exception
is not caught by the service and propagates to the base pipeline, whose handling
is opaque.†

| Aspect | Finding |
| --- | --- |
| Resolution timing | DI factory (per scope) |
| Caching | Not cached by the service |
| Failure behavior | Exception propagates to the `CoreAPIStartup` pipeline; resulting status code not determined from source |

## Hosting configuration

### web.config (IIS / ANCM)

| Element | Setting | Purpose |
| --- | --- | --- |
| `<aspNetCore>` | `hostingModel="InProcess"` | ASP.NET Core Module hosting model |
| `<aspNetCore>` | `processPath="dotnet"` `arguments=".\bin\Debug\net6.0\SAIF.Premium.Api.dll"` | Process launch; the `arguments` value targets `net6.0` while the project targets `net8.0` - stale, recorded in Tech debt |
| `<handlers>` | `aspNetCore` -> `AspNetCoreModuleV2` | Routes requests to the ASP.NET Core Module |
| `<environmentVariables>` | `ASPNETCORE_ENVIRONMENT` = `Development` | Has no effect: `Startup` overwrites the environment name from `AppSettings:ApplicationHost` at `src/SAIF.Premium.Api/Startup.cs:23` |

### launchSettings.json

| Profile | Command | Environment | Purpose |
| --- | --- | --- | --- |
| `SAIF.Premium.Api` | `Project` | `ASPNETCORE_ENVIRONMENT=Development` | Local development launch only |
| `IIS Express` | `IISExpress` | `ASPNETCORE_ENVIRONMENT=Development` | Local development launch only |

### Developer request tooling

| File | Purpose |
| --- | --- |
| `SAIF.Premium.Api.http` | Hand-run sample requests against the premium, class-code and admin endpoints |
| `env/.env.dev`, `env/.env.test` | Per-environment variables for the `.http` file (DEV and TEST) |

No environment variable is read by name in source. `ASPNETCORE_ENVIRONMENT` is
the only one set, in `web.config` and `launchSettings.json`, and the service
overrides its effect.

## Serialization configuration

| Setting | Finding | Configured in |
| --- | --- | --- |
| Serializer | `System.Text.Json` (default) | `src/SAIF.Premium.Api/Startup.cs:35` |
| Serializer options | `AddJsonOptions(opt => opt.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()))` | `src/SAIF.Premium.Api/Startup.cs:36` |
| Output formatters | JSON only | `src/SAIF.Premium.Api/Startup.cs` |

## Logging configuration

| Aspect | Finding |
| --- | --- |
| Logging surface | `ILogger<T>` and `ISaifLogService` |
| Log levels | `Logging:LogLevel` in `appsettings.json` and `appsettings.Development.json` |
| Sink / telemetry | Not determined from source; the OpenTelemetry owner is set in `src/SAIF.Premium.Api/Program.cs:14` and no exporter is configured in the repository |
| Configured in | `src/SAIF.Premium.Api/appsettings.json` |

## Environment variance

Values are pipeline-seeded from `environmentsettings/settings.yml`, which the
release pipeline loads into the Environment API for each track; no code path
opens the file.

| Setting | DEV | TEST | PROD | Notes |
| --- | --- | --- | --- | --- |
| `oracledatabase` | one database per track | one database per track | one database per track | Values differ on every track; none is reproduced here |
| `ratetablecacheminutes` | `5` | `5` | `30` | PROD caches rate tables longer |
| `batchsigningkey` | varies | varies | varies | Secure; the value differs per track and is never shown |

`environmentsettings/settings.yml` also seeds a `legacyfeedurl` key that no code
in this repository reads; it may be stale and is recorded in Tech debt.

## Related documentation
- [API index](index.md)
- [Overview](overview.md)
- [Architecture](architecture.md)
- [Hosting pipeline](hosting-pipeline.md)
- [Endpoints](endpoints.md)
- [Authentication and authorization](authentication-authorization.md)
- [Dependencies](dependencies.md)
- [Operations and processes](operations-processes.md)
- [Business rules](business-rules.md)
- [Data model](data-model.md)
- [Operational runbook](operational-runbook.md)
- [Tech debt](tech-debt.md)

> **Note:** Statements marked with † were retrieved from dependency library documentation
> via the Legends CLI RAG service. They describe inherited behavior from the indicated
> origin library and should be verified if the dependency version changes.

## Sources
- `src/SAIF.Premium.Api/appsettings.json`
- `src/SAIF.Premium.Api/appsettings.Development.json`
- `src/SAIF.Premium.Api/Startup.cs`
- `src/SAIF.Premium.Api/Program.cs`
- `src/SAIF.Premium.Api/Configuration/ConfigureUnitOfWorkOptions.cs`
- `src/SAIF.Premium.Api/Services/BatchRecalculationService.cs`
- `src/SAIF.Premium.Api/Services/RateTableCache.cs`
- `src/SAIF.Premium.Api/Services/BatchRequestSigner.cs`
- `src/SAIF.Premium.Api/web.config`
- `src/SAIF.Premium.Api/Properties/launchSettings.json`
- `src/SAIF.Premium.Api/SAIF.Premium.Api.http`
- `environmentsettings/settings.yml`