Startup Validation¶
Deepstaging validates your application at startup so production failures are caught before the first request, not at 3 AM.
Development-Only Services¶
Most modules ship with in-memory implementations for rapid prototyping. These are marked [DevelopmentOnly]:
| Service | Default Implementation |
|---|---|
IFileStore |
InMemoryFileStore |
ISearchIndex<T> |
InMemorySearchIndex<T> |
IVectorIndex<T> |
InMemoryVectorIndex<T> |
ICacheStore |
InMemoryCacheStore |
IAuditStore |
InMemoryAuditStore |
IJobScheduler |
InMemoryJobScheduler |
IJobStore |
InMemoryJobStore |
INotificationChannel |
NoOpNotificationChannel |
INotificationStore |
InMemoryNotificationStore |
IUserContext |
StubUserContext |
In development, these just work — register your runtime and start building. In production, the bootstrapper detects any [DevelopmentOnly] service still registered and fails at startup with a clear message:
Deepstaging: Development-only services detected in production environment.
The following services are tagged with [DevelopmentOnly] and must be replaced
with production implementations before deploying:
- InMemoryFileStore (registered as IFileStore)
- InMemoryAuditStore (registered as IAuditStore)
To resolve this, register production implementations
or explicitly acknowledge development services with
opts.AcknowledgeDevelopmentService<T>().
How It Works¶
The bootstrapper snapshots all registered services at configuration time. A BackgroundService runs at startup, checks the environment, and throws if any [DevelopmentOnly] implementation is registered in a production host.
Replacing with Production Implementations¶
Register a real implementation before the runtime bootstrapper — TryAdd semantics ensure the production version wins:
// Production implementation registered first
services.AddSingleton<IFileStore, AzureBlobFileStore>();
services.AddSingleton<IAuditStore, PostgresAuditStore>();
// In-memory defaults won't override
builder.AddAppRuntime();
Acknowledging Development Services¶
Sometimes you intentionally want a development implementation in production — for example, using InMemorySearchIndex<T> while search isn't a priority yet. Use AcknowledgeDevelopmentService<T>() to suppress the check:
builder.AddAppRuntime(options =>
{
options.AcknowledgeDevelopmentService<InMemorySearchIndex<Product>>();
});
This is an explicit opt-in. The startup check passes, but you've documented the decision in code.
Configuration Validation¶
Configuration providers generate .ValidateOnStart() checks for every required property. If a config section is missing or incomplete, the app fails at startup:
Configuration section 'Smtp:SmtpSettings' is not configured.
Ensure all required values are set in deepstaging.settings.json or user-secrets.
Required properties are validated individually:
These run during host startup — before any request is handled.
Secret Safety¶
The Auth module validates JWT configuration at startup:
- Secret length — JWT secret must be at least 32 characters
- Insecure patterns — known development defaults (e.g.,
"secret","changeme") cause a warning in development and a startup failure in production
Insecure JWT secret detected in production.
Set a strong, unique Auth:JwtSecret value for production deployments.
Capability Validation¶
The generated ValidateAppRuntime() method eagerly resolves every service the runtime depends on. Call it after building the host to catch missing DI registrations immediately:
If any capability is missing from the container, this throws before the app starts listening — not when the first handler runs.