Skip to content

Deployment — Configuration

How settings reach the NKO ERP, every key it reads, what the environment name changes, and the settings that no configuration can reach because they are compiled in.

Where settings come from

Program.cs uses Host.CreateDefaultBuilder, so ASP.NET Core loads configuration from these sources. Later sources override earlier ones:

# Source Notes
1 appsettings.json Not committed — it holds live connection strings and AWS keys. appsettings.example.json is the committed template.
2 appsettings.{Environment}.json e.g. appsettings.Production.json
3 User secrets Development only. The project has a UserSecretsId, so dotnet user-secrets works on a developer machine.
4 Environment variables Use __ for : — ConnectionStrings__HrConnection
5 Command-line arguments

Prefer environment variables for production secrets

Because environment variables override appsettings.json, production credentials can be kept out of files on disk entirely. Under IIS they can be set per site in the web.config that dotnet publish generates (<environmentVariables>), or as app-pool environment variables.

What ASPNETCORE_ENVIRONMENT changes

Very little. When unset, ASP.NET Core assumes Production. In this application the environment name affects exactly three things:

Effect Development Anything else
UseHsts() off on
appsettings.{Environment}.json appsettings.Development.json e.g. appsettings.Production.json
User secrets loaded yes no

It does not switch off the developer exception page — UseDeveloperExceptionPage() runs unconditionally, so full stack traces are shown in every environment (R1-1). Both launch profiles in Properties/launchSettings.json set Development; that file is local and is not published.

Every key the application reads

From appsettings.example.json, checked against the classes the configuration binds to (BaseAppSettings, StorageConfigs, ScheduledJobsSettings) and against direct reads in Startup.cs.

Key Required Read by Purpose
ConnectionStrings:HrConnection yes AddDbContext<NKO_DBEntities1> Core database NKO_DB
ConnectionStrings:WareConnection yes AddDbContext<WarehouseDBContext> Warehouse database NKO_DB_Warehouse
ConnectionStrings:HangfireConnection yes UseSqlServerStorage Hangfire job store. The database must exist; Hangfire creates its schema (PrepareSchemaIfNecessary = true).
StorageConfigs:region yes Startup — S3 options AWS region. Startup reads it while registering S3, so without it the application does not start.
StorageConfigs:clientId / clientSecret yes Startup AWS credentials, used for S3 (and for the unused SNS client, R1-4)
StorageConfigs:Systems yes S3ServiceHandler Bucket and folder per feature — see below
SysUrl yes CommonController Base URL prefixed to a notification’s ContentUrl when the notification list redirects to the document (SysUrl + ContentUrl, in four places). ContentUrl is stored without a leading slash — "grn/details/…" — so SysUrl must end with /. Links inside e-mails do not use this key: they are built from the compiled-in SiteSettings.SystemURL (R4-4).
System no top bar Only highlights the HR menu when set to "HR"
ScheduledJobsSettings:BirthdayGreetingsIsActive no BirthdayGreetingsJob false disables the job. It is a plain bool, so if the ScheduledJobsSettings section exists but this key is missing it defaults to false and the job is off; if the whole section is missing, the check is skipped and the job runs. Set it explicitly.
ScheduledJobsSettings:BirthdayGreetingsCronExpression no BirthdayGreetingsJob Defaults to 0 9 * * * (09:00 daily, server time)
EPPlus:ExcelPackage:LicenseContext yes EPPlus NonCommercial — check the licence terms (R1-8)
Logging:LogLevel:* no framework Affects framework and EF output only; the application itself logs almost nothing (R8-7)
AllowedHosts no host filtering * in the example — see below

Two keys that appear elsewhere are not needed:

  • JwtConfig:Secret — read only inside the AddJwtBearer(...) options callback, which ASP.NET Core runs only if the JWT scheme is ever used. It never is: AddIdentity makes the Identity cookie the default scheme (R6-4). Neither the example nor a working configuration defines it.
  • StorageConfigs:Bucket — a property on StorageConfigs that nothing reads. The bucket comes from Systems.

StorageConfigs

Every upload and download names a Functionality, and S3ServiceHandler looks it up with:

var system = _settings.StorageConfigs.Systems.First(x => x.Functionality == functionality);

First throws when there is no match. So Systems must contain an entry for every value of the Functionality enum — there are 19:

"StorageConfigs": {
  "region": "…", "clientId": "…", "clientSecret": "…",
  "Systems": [
    { "Functionality": "NKOHR",              "BucketName": "…", "Folder": "Attachments" },
    { "Functionality": "NKOWarehouse",       "BucketName": "…", "Folder": "Attachments" },
    { "Functionality": "NKOLeaves",          "BucketName": "…", "Folder": "Leaves" },
    { "Functionality": "NKOTemplates",       "BucketName": "…", "Folder": "Templates" },
    { "Functionality": "NKOCharges",         "BucketName": "…", "Folder": "Charges" },
    { "Functionality": "NKOPR",              "BucketName": "…", "Folder": "PR" },
    { "Functionality": "NKOJustification",   "BucketName": "…", "Folder": "Justification" },
    { "Functionality": "NKOPOJustification", "BucketName": "…", "Folder": "POJustification" },
    { "Functionality": "NKOPO",              "BucketName": "…", "Folder": "PO" },
    { "Functionality": "NKOGRN",             "BucketName": "…", "Folder": "GRN" },
    { "Functionality": "NKOPTO",             "BucketName": "…", "Folder": "PTO" },
    { "Functionality": "NKORFQQuote",        "BucketName": "…", "Folder": "RFQQuote" },
    { "Functionality": "NKORFQTech",         "BucketName": "…", "Folder": "RFQTech" },
    { "Functionality": "NKORFQPortfolio",    "BucketName": "…", "Folder": "RFQPortfolio" },
    { "Functionality": "NKOOvertimes",       "BucketName": "…", "Folder": "Overtimes" },
    { "Functionality": "NKOProjects",        "BucketName": "…", "Folder": "Projects" },
    { "Functionality": "NKOGeneral",         "BucketName": "…", "Folder": "General" },
    { "Functionality": "NKOJobApplication",  "BucketName": "…", "Folder": "JobApplication" },
    { "Functionality": "NKODestruction",     "BucketName": "…", "Folder": "Destruction" }
  ]
}

NKODestruction is missing — asset-disposal uploads always fail (R4-1)

The committed appsettings.example.json lists 18 entries and omits NKODestruction, and a working configuration built from it has the same gap. DestructionController.UploadFiles uploads with Functionality.NKODestruction, so First throws InvalidOperationException; neither UploadFileToS3 (which rethrows) nor the action catches it, and the user gets the developer exception page (R1-1). Adding the last entry above fixes it — the folder name Destruction is a suggestion; nothing in the code prescribes it.

AllowedHosts

"*" disables host-header filtering. Set it to the site's real host name in production. Besides the usual reason — rejecting requests for host names the site does not serve — it matters here because Url.Action(..., "https") builds absolute URLs from the request's Host header, and wkhtmltopdf then fetches those URLs from the server itself when rendering PDF headers (see Server Requirements).

Settings that are compiled in

These cannot be changed by configuration. Changing any of them means editing source and rebuilding — and therefore a separate build per environment (R4-4):

Setting File
Site name, SystemURL, SiteURL, JobCenterURL, JobCenterRFQURL, SiteVacancyURL NKO.Shared/Helpers/SiteSettings.cs
HREmail, SystemEmail, AutoReplyEmail and both mailbox passwords (R1-9) NKO.Shared/Helpers/SiteSettings.cs
TemplatePath — C:\upload\nko\templates\ NKO.Shared/Helpers/SiteSettings.cs
LowerSiteName — nko, used to build C:\upload\nko\… paths NKO.Shared/Helpers/SiteSettings.cs
Every other C:\upload\… path (R4-2) several controllers and ExportHelper
SMTP host smtp.office365.com, port 587 NKO.Shared/Helpers/EmailManager.cs
data.fixer.io access key — for a client that is never called (R7-17) NKO.Main/BAL/BExchangeRate.cs

A test build carries the test URLs and mailbox; promoting it to production sends production users links to the test site. Build once per environment, from a commit where SiteSettings.cs matches that environment.