Compile-time safety · configuration
Catching broken appsettings before deployment.
Configuration is code with none of code’s usual protection. A one-letter section typo can compile cleanly, pass review and wait until startup to introduce itself.
Strongly typed Options make configuration pleasant to consume. They do not make the configuration itself strongly typed. The C# model and the JSON file can drift in separate pull requests, with separate reviewers, and the compiler is perfectly happy with both.
That gap explains a familiar class of production failure: the application builds, the
deployment succeeds, and the process then discovers that a section was renamed, a required
value is absent or the string "eighty" will not bind to an integer port.
Binding is not validation
This registration creates an Options object, but by itself it does not prove the section exists or force every validation rule to run when the application starts.
services.AddOptions<PaymentsOptions>()
.BindConfiguration("Paymnets"); // typo compiles cleanly Data annotations and startup validation close part of the gap. They turn missing required values into an early process failure instead of a later null reference or bad request.
services.AddOptions<PaymentsOptions>()
.BindConfiguration("Payments")
.ValidateDataAnnotations()
.ValidateOnStart(); The failures that remain
Even a careful registration leaves questions the compiler normally cannot answer:
- Does
Paymentsexist in any visibleappsettings*.jsonfile? - Does every required Options property have a matching key?
- Is a JSON key merely unknown, or will strict binding make it fatal?
- Can the configured scalar convert to the target CLR type?
- Are nested Options objects being validated recursively?
Integration tests can answer those questions, but only for the configuration files and environment combinations the test loads. Production overrides, renamed properties and small spelling mistakes still have room to hide.
Treat JSON as part of the program
An analyser can inspect the Options registrations and the JSON additional files together. When both sides are statically visible, it can join the section literal to the document, walk the Options shape and report the mismatch on the line the developer is editing.
The important boundary is certainty. A dynamic section name, a custom configuration provider or a value assembled at runtime should not produce a confident warning. High-signal tooling reports what it can prove and stays quiet where the runtime owns the answer.
Generate the contract in the other direction
The same Options model can also produce a JSON Schema. Point the editor at that schema and
appsettings.json gains autocomplete, type checks, required-key hints and
unknown-property warnings before the application is built.
dotnet tool install --global ConfigContraband.Tool
configcontraband schema --project src/MyApp/MyApp.csproj ConfigContraband applies both sides of that approach: Roslyn diagnostics for provable configuration drift and a companion schema tool for live JSON guidance. The deployment should still validate its real environment. It simply should not be the first place a spelling mistake gets a fair hearing.
If configuration can stop the application, it deserves feedback before the application starts.