Skip to main content

Outline

At a glance
  • Focus: Environment-specific settings in Optimizely DXP without brittle manual hacks
  • Core model: Layered configuration using JSON files, User Secrets, and environment variables
  • Recommended pattern: Let configuration supply values instead of hardcoding environment-specific logic
  • Operational goal: Promote the same build from Integration to Production without changing code

Mastering environment-specific configuration is one of the definitive hallmarks of a senior Optimizely PaaS developer. In a Digital Experience Platform (DXP) context, your code is a "global citizen" that travels through multiple gated stages: your Local Development Station, the Integration sandbox, the Pre-production staging mirror, and finally, the live Production delivery engine.

A common architectural failure—often referred to as a "brittle hack"—is the reliance on manual toggles, hardcoded conditional blocks based on machine names, or complex #if DEBUG pre-processor directives. These patterns lead to "deployment anxiety" where a build works perfectly in Integration but fails in Production due to a missing manual step. This module explores how to leverage the native .NET 10 configuration ecosystem to build a "write once, run anywhere" solution that is secure, maintainable, and truly cloud-native.

1. The Architectural Foundation: Order of Precedence

Optimizely CMS 13 fully embraces the modern ASP.NET Core configuration provider model. This model isn't just about reading a file; it is an aggregated hierarchy of key-value pairs that are layered on top of each other. The logic is simple: The last provider loaded wins.

The Professional Loading Chain

  1. appsettings.json: This is your "Base Layer." Use it for settings that are structurally identical across all environments, such as default UI culture or content-agnostic business rules.
  2. appsettings.{Environment}.json: This is your "Delta Layer." When the application initializes, it checks the ASPNETCORE_ENVIRONMENT variable. If it's set to Integration, it loads appsettings.Integration.json, overwriting any colliding keys from the base file.
  3. User Secrets (Local Only): This is your "Security Buffer." During local development, sensitive keys (like a private API token for a test ERP) should be stored here. This prevents secrets from ever touching your Git repository.
  4. Environment Variables (The Ultimate Override): In the DXP (Azure) ecosystem, any setting provided via the PaaS Portal configuration tab is injected as an environment variable. These are loaded last and will overwrite even your production JSON files.
The Golden Rule of PaaS Security

Never, under any circumstances, commit a production API key, password, or client secret to an appsettings.json file. If a file is in source control, it is potentially public.

2. Professional Strategy: Environment-Specific Deltas

Instead of writing code that asks "Am I in production?", you should design your code to ask "What is the value of this setting?" and let the configuration layer provide the answer based on the environment.

Example: API Endpoint Management

Consider a real-world scenario where your CMS must communicate with a Corporate Identity API. You have a developer mock instance and a live production endpoint.

appsettings.Development.json

{ "CmsIntegrations": { "IdentityEndpoint": "https://localhost:7001/mock/auth", "EnableDiagnosticLogging": true } }

appsettings.Production.json

{ "CmsIntegrations": { "IdentityEndpoint": "https://identity.enterprise.com/v2/oauth", "EnableDiagnosticLogging": false } }

By leveraging this structure, the developer simply requests the key via the configuration API, and the runtime automatically resolves the correct URL. This creates a zero-touch deployment experience.

3. Strongly Typed Configurations (The Options Pattern)

Using string-based lookups like _config["Settings:Key"] is a "brittle" pattern because it lacks type safety and IntelliSense. The Options Pattern solves this by binding configuration sections directly to plain C# classes.

Step 1: Define a Validated Configuration Class

public class EnterpriseApiOptions { public const string SectionName = "EnterpriseIntegrations"; [Required] [Url] public string BaseUrl { get; set; } = string.Empty; [Range(5, 60)] public int RequestTimeoutSeconds { get; set; } = 30; }

Step 2: Service Registration in Startup.cs

public void ConfigureServices(IServiceCollection services) { services.Configure<EnterpriseApiOptions>( _configuration.GetSection(EnterpriseApiOptions.SectionName)); }

Step 3: Type-Safe Access via Dependency Injection

public class InventorySyncService { private readonly EnterpriseApiOptions _config; public InventorySyncService(IOptions<EnterpriseApiOptions> options) { _config = options.Value; } public async Task<string> FetchData() { var client = new HttpClient { BaseAddress = new Uri(_config.BaseUrl) }; // Implementation logic... } }

4. DXP Constants and Contextual Identification

While file-based configuration covers most use cases, you occasionally need logic that pivots on environment identity—such as enabling a "Dev-only" dashboard in Integration.

Implementation Best Practice: IWebHostEnvironment

Instead of checking machine names, use the standard .NET IWebHostEnvironment interface. DXP automatically populates the EnvironmentName property.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else if (env.IsEnvironment("Integration")) { app.UseCmsDiagnosticTools(); } else { app.UseHsts(); app.UseExceptionHandler("/error/500"); } }

5. DXP Cloud Runtime Configuration (Injected Variables)

When running in DXP, Optimizely injects platform-managed environment variables. These handles allow your code to connect to the Azure stack without manual configuration.

  • APPINSIGHTS_INSTRUMENTATIONKEY: Routes telemetry to Azure Application Insights.
  • EPiServerDB: The system connection string, inherited via the Cloud Integration package.
  • episerver:EnvironmentName: Historically used by DXP to coordinate automated jobs like cache-purging.

6. Summary for Certification

Success in CMS 13 PaaS development is defined by a build that can be promoted from Integration to Production without a single code change. To pass this module, ensure you can:

  1. Isolate secrets using environment variables.
  2. Organize settings via environment-specific JSON files.
  3. Implement the Type-Safe Options Pattern for all custom integrations.

Conclusion

A reliable configuration strategy in DXP depends on layered settings, environment-aware overrides, and secure secret handling rather than manual edits or hardcoded checks. When developers rely on the native .NET configuration system and strongly typed options, deployments become safer, cleaner, and far more predictable across Integration, Pre-production, and Production.