Skip to content

appsettings Reference

An exhaustive, per-host reference of every appsettings*.json file the Cargonerds solution ships, every configuration key inside them, what each key is for and its committed default value.

This page is the key-level catalogue. For how the files are layered, the precedence order, the two {token} replacement engines and the driving environment variables, read the companion page first:

  • Configuration Settings — the loading pipeline, environment axes (SPARK_ENVIRONMENT / AZURE_ENVIRONMENT), token replacement, and recipes.

Committed secrets

Almost every value in these files is a real production secret — SQL passwords, the SMTP password, the Entra client secret, Google / Algolia / MapTiler / E-adapter / PricingManager API keys, the StringEncryption:DefaultPassPhrase, the OpenIddict CertificatePassPhrase and the ABP AbpLicenseCode. They live in the repo unencrypted. Treat any value shown here as compromised and rotate before relying on it. The example values below are reproduced from the committed files only so the structure is unambiguous.


How a host assembles its configuration

Every host calls builder.AddServiceDefaults() (src/Cargonerds.ServiceDefaults/HostApplicationBuilderExtensions.cs), which layers extra JSON files and two IConfigurationSource rewriters on top of the standard .NET chain. Later layers win.

flowchart TD
    A["appsettings.json"] --> B["appsettings.{ASPNETCORE_ENVIRONMENT}.json"]
    B --> C["User Secrets (Development only)"]
    C --> D["Environment variables / CLI args"]
    D --> E{"USE_ASPIRE_CONFIG = true?"}
    E -- yes --> F["appsettings.aspire.json"]
    E -- no --> G
    F --> G{"AZURE_ENVIRONMENT set?"}
    G -- yes --> H["appsettings.azure.json + per-segment overlays<br/>then ConfigurationParameters rewriter"]
    G -- no --> I
    H --> I["white-label file<br/>(WHITE_LABEL_SETTINGS_PATH ?? appsettings.rohlig.json)"]
    I --> J["appsettings.spark.&lt;SPARK_ENVIRONMENT&gt;.json"]
    J --> K["appsettings.spark.&lt;env&gt;.user.json"]
    K --> L["ServiceDiscovery rewriter:<br/>resolve {service} tokens"]

Two databases, two connection-string names

ConnectionStrings:Default (constant SparkDb) is the ABP application DB (Identity, OpenIddict, Settings, Features, AuditLogging, CmsKit, Saas, Chat, BLOB-in-DB, and Hangfire storage). ConnectionStrings:Hub (constant HubDb) is the Hub domain DB (shipments, organizations, tracking, pricing). The names are defined once in src/Cargonerds.Domain.Shared/Configuration/ConnectionStringNames.cs: HubDb = "Hub", SparkDb = "Default", BlobStorage, HubServiceBus = "hubServiceBus".


Section glossary (shared across hosts)

These sections appear in more than one host. Per-host tables below reference them rather than repeating the explanation.

Section Bound to / consumed by Meaning
App AppConfiguration (src/Cargonerds.Domain.Shared/Configuration/AppConfiguration.cs) via GetAppConfiguration() Self URL, public URL, CORS list, PII switch, health-check path, customer id, booking-number prefix. See the App section table.
ConnectionStrings IConfiguration.GetConnectionString(...) Default, Hub, BlobStorage, hubServiceBus, plus Aspire redis / messaging.
AuthServer JWT bearer + OpenIddict + OIDC clients Authority, RequireHttpsMetadata, MetaAddress, SwaggerClientId, ClientId / ClientSecret, CertificatePassPhrase, ResponseType, WellKnownConfigAddress.
Redis Redis:Configuration read directly in modules StackExchange connection string for DataProtection key persistence and the distributed-lock provider.
RabbitMQ AbpRabbitMqOptions via ConfigureRabbitMQ Connections:Default:HostName, Connections:Default:Override, EventBus:ClientName, EventBus:ExchangeName.
StringEncryption ABP AbpStringEncryptionOptions DefaultPassPhrase used to decrypt the encrypted SMTP password and other encrypted settings.
Settings ABP setting defaults seeded at startup Abp.Mailing.Smtp.* and mail from-address defaults.
WhiteLabelingOptions WhiteLabelingOptions (modules/hub/src/Hub.Domain.Shared/WhiteLabeling/WhiteLabelingOptions.cs) via GetRequiredValue<WhiteLabelingOptions>(...) Branding, EntraLogins, ExternalApis. See the White-label section.
RemoteServices ABP dynamic C# client proxies Default:BaseUrl, AbpAccountPublic:BaseUrl — where a host calls the API / auth server.
OpenIddict OpenIddict app seeding Applications[] — OIDC client definitions seeded into the DB.
Logging .NET logging LogLevel map.
AbpLicenseCode ABP AddAppSettingsSecretsJson() The ABP commercial license; lives only in appsettings.secrets.json.

ABP-pattern background: Settings, Features, Distributed cache, BLOB storing, OpenIddict / auth server, Background jobs.

The App section

App binds to AppConfiguration. Not every host sets every property; the table is the union.

Key Type Purpose Typical local default
App:SelfUrl string This host's own public base URL (issuer/redirect base). per host, e.g. https://localhost:44354 (API), :44345 (Auth), :44332 (Web.Public), :44381 (Blazor)
App:MVCPublicUrl string URL of the public MVC/Web site (AppUrlOptions.Applications["MVCPublic"]). https://localhost:44332 (API)
App:CorsOrigins string (comma-list) Allowed CORS origins. wildcard *.rohlig.com / *.cargonerds.com / *.cargonerds.dev + localhost ports
App:RedirectAllowedUrls string (comma-list) Allowed post-login redirect URLs (AppUrlOptions.RedirectAllowedUrls); AuthServer also merges App:AllowedRedirectUrls. wildcard + localhost (AuthServer)
App:DisablePII bool Disables logging of personally identifiable info. false
App:HealthCheckUrl string Path of the health-status UI page. /health-status
App:CargonerdsCustomerId Guid Tenant/customer id that scopes Hub data; set per Spark env. (none locally) / 2D524F51-… for dev/test/prod
App:BookingNumberPrefix string Prefix for generated booking numbers; per Spark env. empty (local/prod), Booking- (dev)
App:AllowedCorsOrigins string/array Aspire-template variant of the CORS list (token form). {realtime} / ["{api}","{realtime}","{admin}"]
App:AllowedRedirectUrls array Aspire-template redirect allow-list (AuthServer). ["{api}","{realtime}","{admin}"]
App:Realtime string URL of the realtime (React) front-end. {realtime} (API aspire file)

AuthServer — src/Cargonerds.AuthServer/

The OpenIddict authority. Module: CargonerdsAuthServerModule.cs.

File Loaded Contents
appsettings.json always App, ConnectionStrings:Default, AuthServer, StringEncryption, Redis.
appsettings.Development.json Development empty {}.
appsettings.aspire.json USE_ASPIRE_CONFIG=true token template — see below.
appsettings.secrets.json via AddAppSettingsSecretsJson() AbpLicenseCode only.

appsettings.json keys

Key Default Purpose
App:SelfUrl https://localhost:44345 AuthServer base URL → OpenIddict issuer + MVC root.
App:CorsOrigins wildcard + localhost list CORS origins.
App:RedirectAllowedUrls wildcard + localhost list Login/logout redirect allow-list.
App:DisablePII false PII logging switch.
App:HealthCheckUrl /health-status Health UI path.
ConnectionStrings:Default Server=(LocalDb)\MSSQLLocalDB;Database=CargonerdsAppDb;Trusted_Connection=True;TrustServerCertificate=true ABP application DB.
AuthServer:Authority https://localhost:44345 OpenIddict issuer (SetIssuer).
AuthServer:RequireHttpsMetadata true When false, disables transport-security requirement and enables X-Forwarded-Proto handling (reverse-proxy deploys).
AuthServer:CertificatePassPhrase (committed in Dev file) Passphrase for openiddict.pfx in non-Development.
StringEncryption:DefaultPassPhrase vd7i8105O0jZ7xQl ABP string-encryption key.
Redis:Configuration 127.0.0.1 Redis endpoint for DataProtection persistence (non-Development) and distributed lock.

Where the OpenIddict certificate passphrase actually lives

appsettings.json does not contain AuthServer:CertificatePassPhrase. It is set in appsettings.Development.json (d9efcd01-fbd8-42b1-a9d1-a5cf44afe714). In non-Development, CargonerdsAuthServerModule.PreConfigureServices calls AddProductionEncryptionAndSigningCertificate("openiddict.pfx", configuration["AuthServer:CertificatePassPhrase"]). In Development, ABP's auto-generated dev certificate is used instead.

appsettings.aspire.json (token template)

Uses service-discovery {token}s resolved from Aspire endpoints / connection strings.

{
  "App": {
    "SelfUrl": "{auth}",
    "AllowedCorsOrigins": ["{api}", "{realtime}", "{admin}"],
    "AllowedRedirectUrls": ["{api}", "{realtime}", "{admin}"]
  },
  "AuthServer": {
    "Authority": "{auth}",
    "WellKnownConfigAddress": "{auth}/.well-known/openid-configuration"
  },
  "Redis": { "Configuration": "{redis}" },
  "RabbitMQ": { "Connections": { "Default": { "HostName": "{messaging}", "Override": true } } }
}
Token key Resolves to
App:SelfUrl = {auth} The AuthServer's own Aspire endpoint.
App:AllowedCorsOrigins / App:AllowedRedirectUrls {api}, {realtime}, {admin} endpoints (merged into RedirectAllowedUrls).
AuthServer:Authority = {auth} Issuer.
AuthServer:WellKnownConfigAddress {auth}/.well-known/openid-configuration.
Redis:Configuration = {redis} ConnectionStrings:redis.
RabbitMQ:Connections:Default:HostName = {messaging} (Override:true) ConnectionStrings:messaging AMQP URI; Override triggers URI parsing — see Cross-cutting gotchas.

HttpApi.Host — src/Cargonerds.HttpApi.Host/

The REST/OData API and the only host that ships the per-Spark-env files. Module: CargonerdsHttpApiHostModule.cs.

File Loaded Contents
appsettings.json always Settings, App, ConnectionStrings:Default, Redis, RabbitMQ, AuthServer, StringEncryption.
appsettings.Development.json Development empty {}.
appsettings.aspire.json USE_ASPIRE_CONFIG=true token template.
appsettings.secrets.json AddAppSettingsSecretsJson() AbpLicenseCode.
appsettings.spark.<env>.json per SPARK_ENVIRONMENT (reloadOnChange) Hub/BlobStorage/hubServiceBus connection strings + per-env App + per-env WhiteLabelingOptions:ExternalApis.
appsettings.spark.<env>.user.json per env (reloadOnChange) developer-local overrides; only the local variant is gitignored.

appsettings.json keys

Key Default Purpose
Settings:Abp.Mailing.Smtp.Host smtp.office365.com SMTP host (seeded ABP setting default).
Settings:Abp.Mailing.Smtp.Port 587 SMTP port.
Settings:Abp.Mailing.Smtp.UserName smtp.cargonerds@cargonerds.com SMTP user.
Settings:Abp.Mailing.Smtp.Password 4aJ38… (// Encrypted) SMTP password, encrypted with StringEncryption:DefaultPassPhrase.
Settings:Abp.Mailing.Smtp.EnableSsl true TLS.
Settings:Abp.Mailing.Smtp.UseDefaultCredentials false Use explicit creds.
Settings:Abp.Mailing.DefaultFromAddress smtp.cargonerds@cargonerds.com Default From.
Settings:Abp.Mailing.DefaultFromDisplayName Cargonerds Mail Default From display name.
App:SelfUrl https://localhost:44354 API base URL.
App:MVCPublicUrl https://localhost:44332 Public web URL.
App:CorsOrigins wildcard + localhost list CORS origins.
App:DisablePII false PII switch.
App:HealthCheckUrl /health-status Health UI path.
ConnectionStrings:Default Server=(LocalDb)\MSSQLLocalDB;Database=CargonerdsAppDb;… ABP application DB + Hangfire storage.
Redis:Configuration 127.0.0.1 Redis endpoint (DataProtection / distributed lock).
RabbitMQ:Connections:Default:HostName localhost AMQP host.
RabbitMQ:EventBus:ClientName HttpApiHost Distributed event-bus client name.
RabbitMQ:EventBus:ExchangeName Cargonerds Exchange name.
AuthServer:Authority https://localhost:44345 JWT issuer/authority (AddAbpJwtBearer).
AuthServer:RequireHttpsMetadata true HTTPS metadata requirement.
AuthServer:MetaAddress https://localhost:44345 OIDC metadata address.
AuthServer:SwaggerClientId api Client id used by the Swagger OIDC flow.
StringEncryption:DefaultPassPhrase vd7i8105O0jZ7xQl String-encryption key.

Fixed values set in code (not appsettings)

The JWT bearer Audience is hard-coded to "Cargonerds", and the distributed cache KeyPrefix is built in code as "Cargonerds:", suffixed with "<AZURE_ENVIRONMENT>:" when that variable is set (ConfigureCache). Neither is a configuration key. DataProtection keys persist to Redis under Cargonerds-Protection-Keys (non-Development only).

appsettings.aspire.json (token template)

{
  "App": {
    "SelfUrl": "{api}",
    "AllowedCorsOrigins": "{realtime}",
    "CorsOrigins": "{realtime},{admin}",
    "Realtime": "{realtime}"
  },
  "AuthServer": {
    "Authority": "{auth}",
    "MetaAddress": "{auth}",
    "WellKnownConfigAddress": "{auth}/.well-known/openid-configuration"
  },
  "Redis": { "Configuration": "{redis}" },
  "RabbitMQ": { "Connections": { "Default": { "HostName": "{messaging}", "Override": true } } }
}

Spark files — Hub data-source selection

SPARK_ENVIRONMENT picks one file; it carries the Hub DB, BlobStorage, hubServiceBus and the per-env App:CargonerdsCustomerId / BookingNumberPrefix. Some files also override WhiteLabelingOptions:ExternalApis (PricingManager, E-adapter) for that backend.

Key (in every spark file) Purpose
App:CargonerdsCustomerId Tenant id for the backend (absent in local).
App:BookingNumberPrefix Booking-number prefix (e.g. Booking- in dev).
ConnectionStrings:Hub Hub domain SQL DB for this backend.
ConnectionStrings:BlobStorage Azure Storage / Azurite account.
ConnectionStrings:hubServiceBus Azure Service Bus namespace (empty for local).
WhiteLabelingOptions:ExternalApis:PricingManager / :Eadapter Per-env pricing / E-adapter overrides (present in dev/test/prod/prod-read-only).
Spark env Hub DB server Blob storage Service bus Notes
local localhost,1401 db hub-main, user sa Azurite devstoreaccount1 on :10100 empty offline dev; BookingNumberPrefix empty.
dev sql-cargonerds-db-gerwc-development app user cnhubgerwcdevelopment cn-hub-gerwc-development BookingNumberPrefix=Booking-.
test sql-cargonerds-db-gerwc-test app user cnhubgerwctest cn-hub-gerwc-test E-adapter ServerId=TRN.
prod sql-cargonerds-db-gerwc-production app user cnhubgerwcproduction cn-hub-gerwc-production E-adapter ServerId=SYD; prod pricing URL.
prod-read-only same prod DB, read user cnhubgerwcproduction cn-hub-gerwc-production read-only SQL credential; only PricingManager overridden.

The Hub pool reads ConnectionStrings:Hub directly with retry + a 3-minute command timeout (HubEntityFrameworkCoreModule.cs):

var cs = sp.GetRequiredService<IConfiguration>().GetConnectionString(ConnectionStringNames.HubDb);
opts.UseSqlServer(cs, sql => { sql.EnableRetryOnFailure(); sql.CommandTimeout((int)TimeSpan.FromMinutes(3).TotalSeconds); });
// AddDbContextPool<HubDbContext>(..., poolSize: 256)

Blazor admin server — src/Cargonerds.Blazor/

The ABP/LeptonX admin UI host. It ships no committed root appsettings.json — it relies entirely on the layered files plus Aspire env vars.

File Loaded Contents
appsettings.aspire.json USE_ASPIRE_CONFIG=true token template, wrapped in a ClientConfiguration root.
{
  "ClientConfiguration": {
    "App": { "SelfUrl": "{admin}" },
    "AuthServer": {
      "Authority": "{auth}",
      "WellKnownConfigAddress": "{auth}/.well-known/openid-configuration"
    },
    "RemoteServices": {
      "Default": { "BaseUrl": "{api}" },
      "AbpAccountPublic": { "BaseUrl": "{api}" }
    }
  }
}

ClientConfiguration wrapper is Blazor-specific

Unlike the other hosts, the admin Blazor appsettings.aspire.json nests its settings under a ClientConfiguration root (the values are forwarded to the Blazor WebAssembly client). App:SelfUrl={admin}, AuthServer:Authority={auth}, RemoteServices:Default:BaseUrl={api} and RemoteServices:AbpAccountPublic:BaseUrl={api}.

Blazor WebAssembly client — src/Cargonerds.Blazor.Client/wwwroot/

The WASM client is served statically and does not go through the AddServiceDefaults() pipeline; its config is plain static JSON.

File Contents
wwwroot/appsettings.json committed localhost wiring (see keys below).
wwwroot/appsettings.Development.json {} (empty).

wwwroot/appsettings.json keys:

Key Default Purpose
Logging:LogLevel:* Default=Warning, framework loggers Warning Client log levels.
App:SelfUrl https://localhost:44381 The Blazor admin client's own base URL.
AuthServer:Authority https://localhost:44345 OIDC authority.
AuthServer:ClientId admin OIDC client id used by the WASM client.
AuthServer:ResponseType code Authorization-code flow.
RemoteServices:Default:BaseUrl https://localhost:44354 API base.
RemoteServices:AbpAccountPublic:BaseUrl https://localhost:44354 Account API base.
ConnectivityCheck:Enabled false Toggle for the client connectivity probe.
ConnectivityCheck:PingPath /odata Path the connectivity probe pings.

Under Aspire these localhost values are superseded by the ClientConfiguration token template forwarded from the Blazor admin server's appsettings.aspire.json (above).


Web.Public — src/Cargonerds.Web.Public/

The public-facing MVC/Razor site.

File Loaded Contents
appsettings.json always App, Redis, RemoteServices, AuthServer (confidential web client).
appsettings.Development.json Development empty {}.
appsettings.aspire.json USE_ASPIRE_CONFIG=true token template.
appsettings.secrets.json AddAppSettingsSecretsJson() AbpLicenseCode.

appsettings.json keys

Key Default Purpose
App:SelfUrl https://localhost:44332 Public site base URL.
App:DisablePII false PII switch.
App:HealthCheckUrl /health-status Health UI path.
Redis:Configuration 127.0.0.1 Redis (DataProtection / lock).
RemoteServices:Default:BaseUrl https://localhost:44354/ API base for dynamic proxies.
RemoteServices:AbpAccountPublic:BaseUrl https://localhost:44345/ Account API base (AuthServer).
AuthServer:Authority https://localhost:44345 OIDC authority.
AuthServer:RequireHttpsMetadata true HTTPS metadata requirement.
AuthServer:ClientId web Confidential OIDC client id.
AuthServer:ClientSecret 1q2w3e* Confidential client secret.

appsettings.aspire.json (token template)

{
  "App": { "SelfUrl": "{web}" },
  "RemoteServices": {
    "Default": { "BaseUrl": "{api}/" },
    "AbpAccountPublic": { "BaseUrl": "{auth}/" }
  },
  "AuthServer": { "Authority": "{auth}" },
  "Redis": { "Configuration": "{redis}" },
  "RabbitMQ": { "Connections": { "Default": { "HostName": "{messaging}", "Override": true } } }
}

Note the public site's account API points at {auth} here, whereas its committed local appsettings.json points AbpAccountPublic at the AuthServer (:44345) and Default at the API (:44354).


DbMigrator — src/Cargonerds.DbMigrator/

A console app that applies EF Core migrations and seeds data. It composes config a little differently (see Program.cs): it loads appsettings.aspire.json as non-optional when USE_ASPIRE_CONFIG=true, and when AZURE_ENVIRONMENT is set it calls AddAzureJsonFiles(azureEnvironment, "azure.migrator") so the appsettings.azure.migrator.<env>.json overlays load alongside the standard azure files, supplying DB-admin credentials with DDL rights.

File Loaded Contents
appsettings.json always ConnectionStrings:Default, Redis, and an OpenIddict:Applications[] client-seed list (Cargonerds_App, admin, api, web).
appsettings.aspire.json USE_ASPIRE_CONFIG=true (non-optional) Redis/RabbitMQ tokens plus a richer OpenIddict:Applications[] seed (api, realtime, bruno, admin) using {api}/{realtime}/{admin} endpoints.
appsettings.azure.migrator.<env>.json when AZURE_ENVIRONMENT set admin ConnectionStrings:Default + SPARK_ENVIRONMENT.
appsettings.secrets.json AddAppSettingsSecretsJson(false) AbpLicenseCode.

appsettings.json keys

Key Default Purpose
ConnectionStrings:Default Server=(LocalDb)\MSSQLLocalDB;Database=CargonerdsAppDb;… App DB the migrator targets locally. Also read by the design-time factory.
Redis:Configuration 127.0.0.1 Redis (unless --disable-redis).
OpenIddict:Applications[] Cargonerds_App, admin, api, web OIDC clients seeded into the DB (client id, type, grant types, redirect/post-logout URIs, secret).

appsettings.azure.migrator.<env>.json keys

Key Example Purpose
ConnectionStrings:Default …User ID=spark-db-admin-dev;…Database={spark-db-name} Admin SQL user (DDL rights), {spark-db-name} filled by the ConfigurationParameters from the parallel appsettings.azure.<env>.json.
SPARK_ENVIRONMENT dev / prod / prod-read-only Pins the Hub backend for the migrator run.

Variants present: dev, dev.hub-prod, dev.hub-test, prod, prod.staging (the prod.staging overlay only sets SPARK_ENVIRONMENT=prod-read-only).

Runtime flags & the migration-status endpoint

--enable-api boots a slim web host exposing GET /migration/status, guarded by comparing the ?token= query value to the PIPELINE_AUTH_TOKEN config value (returns 503 if the token is not configured). --disable-redis skips Redis. VALIDATE_MIGRATIONS_ONLY=1 validates without applying. Details: Migrations.

Design-time EF factory reads only this file

CargonerdsDbContextFactory reads Default from the DbMigrator project's appsettings.json (no secrets/azure layering). Add-Migration / Update-Database therefore need that connection string pointing at a reachable DB. See Migrations and Entity Framework.


AppHost — src/Cargonerds.AppHost/

The .NET Aspire orchestrator. Its own appsettings*.json only configure logging; the interesting configuration is the white-label file it owns and forwards, and the env vars it sets on child resources (see Aspire integration).

File Loaded Contents
appsettings.json always Logging:LogLevel (Default=Information, Microsoft.AspNetCore=Warning, Aspire.Hosting.Dcp=Warning).
appsettings.Development.json Development Logging:LogLevel (Default=Information, Microsoft.AspNetCore=Warning).
appsettings.rohlig.json the canonical white-label file (linked into ServiceDefaults, copied to every host's output). WhiteLabelingOptions.
appsettings.rohlig.Development.json Development Logging:LogLevel only (Default=Information, Microsoft.AspNetCore=Warning).

AppHost-driving environment variables

The AppHost reads/forwards these (see src/Cargonerds.AppHost/EnvVars.cs). They are env vars, not appsettings keys, but they determine which appsettings files the children load.

Variable Read/Set by Effect
USE_ASPIRE_CONFIG set on each child by AddProjectWithDefaults makes children load appsettings.aspire.json. Mandatory under Aspire.
SPARK_ENVIRONMENT forwarded to children selects the spark file / Hub backend.
WHITE_LABEL_SETTINGS_PATH set by WithWhiteLabelSettingsPath absolute path to appsettings.rohlig.json (children run with their project dir as cwd).
APPHOST_AZURE_ENVIRONMENT read by AppHost (SparkDbRunModeConfiguration) run the local AppHost against an Azure Spark DB.
APPHOST_AZURE_DATABASE_COPY_SUFFIX read by AppHost append a suffix so it targets a copy of the Azure DB.
VALIDATE_MIGRATIONS_ONLY forwarded to migrator validate-only migration mode.
DEPLOYMENT_DOMAIN read by AppHost (publish mode) hostname suffix for services__* in publish mode; throws if missing.
SKIP_WAITING_IN_BACKEND / EXPLICIT_FRONTEND_START read by AppHost local-start convenience toggles.

Cloud / Azure overlays — src/Cargonerds.ServiceDefaults/appsettings.azure*.json

These files are not per host — they live in ServiceDefaults and are loaded by any host (and the migrator) when AZURE_ENVIRONMENT is set. The dotted env name expands cumulatively: AZURE_ENVIRONMENT=dev.hub-test loads appsettings.azure.jsonappsettings.azure.dev.jsonappsettings.azure.dev.hub-test.json, then the ConfigurationParameterReplacementSource rewrites {token}s.

File Sets
appsettings.azure.json Services block (admin/api/web/realtime/auth) with {spark-dev-domain} tokens — the resolution table for service-discovery {api} etc. in cloud.
appsettings.azure.dev.json ConnectionStrings:Default (spark-dev), redis, messaging; SPARK_ENVIRONMENT=dev; ConfigurationParameters (spark-dev-domain=dev, rabbit-mq-port=5672, spark-db-name=spark-dev).
appsettings.azure.prod.json prod Default/redis/messaging; SPARK_ENVIRONMENT=prod; prod ConfigurationParameters; real-hostname Services (*.rt3.rohlig.com).
appsettings.azure.dev.hub-test.json overlay: ConfigurationParameters (spark-db-name=spark-dev-hub-test, rabbit-mq-port=5674) + SPARK_ENVIRONMENT=test.
appsettings.azure.dev.hub-prod.json overlay: ConfigurationParameters (spark-db-name=spark-dev-hub-prod, rabbit-mq-port=5673) + SPARK_ENVIRONMENT=prod-read-only.
appsettings.azure.prod.staging.json overlay: ConfigurationParameters (spark-db-name=spark-prod-staging) + SPARK_ENVIRONMENT=prod-read-only + a Services block re-pointing to {spark-dev-domain}.spark.cargonerds.dev.

Keys in the azure files

Key Purpose
ConnectionStrings:Default The deployment's ABP application (Spark) DB; uses {spark-db-name}.
ConnectionStrings:redis Azure Redis connection string (consumed via Aspire AddRedisClient("redis")).
ConnectionStrings:messaging RabbitMQ AMQP URI; uses {rabbit-mq-port}.
SPARK_ENVIRONMENT Pins the Hub backend for this Azure deployment (this is how the two axes are kept in sync in cloud).
ConfigurationParameters spark-dev-domain, rabbit-mq-port, spark-db-name — substituted into the values above and into Services URLs.
Services:<name>:https[] Public URLs that service-discovery {admin}/{api}/{web}/{realtime}/{auth} tokens resolve to at runtime.
// appsettings.azure.dev.json (abbreviated)
{
  "ConnectionStrings": {
    "Default": "Server=tcp:sql-spark-dev.database.windows.net,1433;User ID=spark-app;Password='…';Initial Catalog={spark-db-name}",
    "messaging": "amqp://sparkuser:…@rabbitmq.dev.spark.cargonerds.dev:{rabbit-mq-port}/"
  },
  "SPARK_ENVIRONMENT": "dev",
  "ConfigurationParameters": { "spark-dev-domain": "dev", "rabbit-mq-port": 5672, "spark-db-name": "spark-dev" }
}

Nested tokens

The Services URLs deliberately nest a ConfigurationParameters token inside a service-discovery target, e.g. "api": { "https": ["https://api.{spark-dev-domain}.spark.cargonerds.dev"] }. {spark-dev-domain} is resolved by the ConfigurationParameters source first; the finished URL then becomes the value that {api} resolves to.


White-label — appsettings.rohlig.json

One canonical file in the AppHost project; linked into ServiceDefaults via the csproj and copied to every host's output. Bound to WhiteLabelingOptions (modules/hub/src/Hub.Domain.Shared/WhiteLabeling/). Spark files override sub-sections of WhiteLabelingOptions:ExternalApis per environment.

Key Type Purpose
AppName string Product name (Realtime).
CompanyName / CompanyNameShort string Röhlig Logistics / Röhlig.
Logo / AppLogo / BackgroundImage / BackgroundVideo / Favicon string Branding asset paths under /_content/Cargonerds.UI.Shared/rohlig/….
DisableCustomUserName bool Hide the custom-username feature (true).
AdditionalJavaScriptFiles / AdditionalStyleSheetFiles string[] Extra JS/CSS injected into the UI.
CopyrightLinks[] / FooterLinks[] FooterLink (Label/Url/Target) Footer/copyright links.
EntraLogins[] EntraLogin (Name/TenantId/ClientId/Secret) Microsoft Entra external-login providers (registered via AddEntraId).
ExternalApis:Google DistanceMatrixApiKey, PlacesApiKey, DistanceUrlTemplate Google Maps keys.
ExternalApis:Algolia AppId, ApiKey, IndexName Algolia search.
ExternalApis:PricingManager Url, ApiKey Pricing engine endpoint (overridden per Spark env).
ExternalApis:Eadapter Url, ApiKey, ServerId, EnterpriseId Röhlig E-adapter (overridden per Spark env; ServerId TRN/SYD).
ExternalApis:MapTiler ApiKey MapTiler tiles.

[PublicConfiguration] controls what reaches the browser

Most WhiteLabelingOptions members carry [PublicConfiguration] so they are exposed to front-ends. EntraLogins is not marked public (it holds the client secret) and is consumed server-side only.


secrets files — appsettings.secrets.json

Loaded by ABP's AddAppSettingsSecretsJson() in every host's Program.cs. In this solution each one contains exactly one key.

Key Purpose
AbpLicenseCode The ABP commercial license (identical copy committed in AuthServer, HttpApi.Host, Web.Public and DbMigrator).

There is no per-developer .NET User Secrets store in play except the UserSecretsId on the AppHost project; everything else is committed JSON.


Cross-cutting gotchas

RabbitMQ override is opt-in and silent

ConfigureRabbitMQ only rewrites AbpRabbitMqOptions when RabbitMQ:Connections:Default:Override == true and the HostName parses as a URI — then it splits the AMQP URI into user/pass/host/port. If Override is false or the value is not a URI, the raw HostName is used verbatim with no warning. The Aspire templates set Override: true so the {messaging} AMQP URI is parsed.

SPARK_ENVIRONMENT typos crash startup

SparkEnvironment.FromName(null) returns Dev, but any unknown non-empty value throws ArgumentException at startup rather than defaulting.

Cache prefix isolates environments on shared Redis

The cache key prefix is Cargonerds: plus <AZURE_ENVIRONMENT>: when set. An empty AZURE_ENVIRONMENT shares the base Cargonerds: prefix.

Edit the source file, not the build copy

appsettings.rohlig.json is copied to every host's bin/ output. There is exactly one editable copy (the AppHost project, plus the TestBase copy used by tests). Editing a bin/.../appsettings.rohlig.json has no lasting effect.

Filename typo

The AppHost helper file is misspelled ConfigruationExtensions.cs — grep for that exact spelling.


See also