The ConfigurationManager shim allows migrated Web Forms code to access application settings and connection strings without modification. Your existing ConfigurationManager.AppSettings["key"] and ConfigurationManager.ConnectionStrings["name"] calls work unchanged in Blazor.
What it does:
- Provides a static
ConfigurationManagerclass in theBlazorWebFormsComponentsnamespace - Enables
AppSettings["key"]access backed by ASP.NET CoreIConfiguration - Enables
ConnectionStrings["name"]access viaGetConnectionString() - Allows migrated Business Logic Layer (BLL) and Data Access Layer (DAL) code to compile and run without code changes
Why it matters:
When migrating a Web Forms application, your BLL/DAL code often uses ConfigurationManager to read database connection strings and application settings. The shim eliminates the need to refactor that code during the initial migration phase, letting you focus on UI layer migration first.
=== "Web Forms (Original)" ```csharp // App_Start/ProductRepository.cs - BLL code using System.Configuration;
public class ProductRepository
{
public ProductRepository()
{
// Access connection string from web.config
string connStr = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
_dbConnection = new SqlConnection(connStr);
}
public void SaveTimeout()
{
// Access app setting from web.config
int timeout = int.Parse(ConfigurationManager.AppSettings["DBTimeout"] ?? "30");
_dbConnection.ConnectionTimeout = timeout;
}
}
// web.config
<configuration>
<connectionStrings>
<add name="DefaultConnection" connectionString="Server=.;Database=MyApp;Integrated Security=true;" />
</connectionStrings>
<appSettings>
<add key="DBTimeout" value="30" />
<add key="ApiKey" value="secret123" />
</appSettings>
</configuration>
```
=== "Blazor with BWFC (Using the Shim)" ```csharp // Shared/ProductRepository.cs - Same code, no changes! using BlazorWebFormsComponents;
public class ProductRepository
{
public ProductRepository()
{
// Same code as Web Forms — ConfigurationManager just works
string connStr = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
_dbConnection = new SqlConnection(connStr);
}
public void SaveTimeout()
{
// Same code as Web Forms
int timeout = int.Parse(ConfigurationManager.AppSettings["DBTimeout"] ?? "30");
_dbConnection.ConnectionTimeout = timeout;
}
}
// appsettings.json (created by L1 migration script)
{
"ConnectionStrings": {
"DefaultConnection": "Server=.;Database=MyApp;Integrated Security=true;"
},
"AppSettings": {
"DBTimeout": "30",
"ApiKey": "secret123"
}
}
```
To enable the shim, call the initialization helper in Program.cs:
// Program.cs
var builder = WebApplication.CreateBuilder(args);
// Register BWFC services and initialize ConfigurationManager shim
builder.Services.AddBlazorWebFormsComponents();
var app = builder.Build();
// ... configure middleware ...
app.Run();The AddBlazorWebFormsComponents() extension automatically initializes the shim with the application's IConfiguration. No additional setup needed.
If you prefer manual control, you can initialize directly:
// Program.cs
builder.Services.AddBlazorWebFormsComponents();
var app = builder.Build();
// Manually initialize if needed (e.g., for unit tests)
BlazorWebFormsComponents.ConfigurationManager.Initialize(app.Services.GetRequiredService<IConfiguration>());
app.Run();The shim reads from ASP.NET Core's IConfiguration in this order:
ConfigurationManager.AppSettings["DBTimeout"]Tries these keys in order:
AppSettings:DBTimeout(from appsettings.json)DBTimeout(flat key)- Returns
nullif not found
This dual-lookup pattern supports both structured config (AppSettings section) and flat keys.
ConfigurationManager.ConnectionStrings["DefaultConnection"]?.ConnectionStringReturns a ConnectionStringSettings object with:
Name— the connection string nameConnectionString— the actual connection stringProviderName— optional ADO.NET provider (default: empty)
Reads from the ConnectionStrings section in appsettings.json, accessed via IConfiguration.GetConnectionString().
The L1 migration script (bwfc-migrate.ps1) automatically converts web.config settings to appsettings.json:
=== "web.config"
xml <configuration> <connectionStrings> <add name="DefaultConnection" connectionString="Server=myserver;Database=mydb;" /> <add name="LegacyDb" connectionString="Server=oldserver;Database=olddb;" /> </connectionStrings> <appSettings> <add key="DBTimeout" value="30" /> <add key="MaxRetries" value="3" /> <add key="FeatureFlag_NewUI" value="true" /> </appSettings> </configuration>
=== "appsettings.json (Migrated)"
json { "ConnectionStrings": { "DefaultConnection": "Server=myserver;Database=mydb;", "LegacyDb": "Server=oldserver;Database=olddb;" }, "AppSettings": { "DBTimeout": "30", "MaxRetries": "3", "FeatureFlag_NewUI": "true" } }
The shim then reads these values exactly as your Web Forms code expects.
For environment-specific overrides, use the standard ASP.NET Core configuration hierarchy:
appsettings.json
↓ (overridden by)
appsettings.Development.json
↓ (overridden by)
appsettings.Production.json
↓ (overridden by)
Environment variables
↓ (overridden by)
User Secrets (Development only)
Example:
// appsettings.json (default)
{
"AppSettings": { "DBTimeout": "30" }
}
// appsettings.Production.json (production override)
{
"AppSettings": { "DBTimeout": "60" }
}When running in Production, ConfigurationManager.AppSettings["DBTimeout"] returns "60".
The shim does not support:
| Feature | Web Forms | BWFC Shim | Alternative |
|---|---|---|---|
| Custom config sections | <custom>...</custom> |
❌ Not supported | Use structured JSON sections in appsettings.json |
| File references | configSource="settings.xml" |
❌ Not supported | Use separate JSON files + ASP.NET Core config providers |
| Encrypted settings | encryptionProvider attribute |
❌ Not supported | Use Azure Key Vault, AWS Secrets Manager, or .NET User Secrets |
| Nested app settings | AppSettings.AppSettings["section"]["key"] |
❌ Not supported | Use structured JSON: "AppSettings": { "Section": { "Key": "value" } } |
If you have custom config sections, migrate them to structured JSON:
// Web Forms: Custom section
<customSettings>
<database host="localhost" port="5432" />
</customSettings>
var dbHost = config.GetSection("customSettings").GetValue<string>("database:host");
// BWFC: Structured JSON
{
"CustomSettings": {
"Database": {
"Host": "localhost",
"Port": 5432
}
}
}
var dbHost = config["CustomSettings:Database:Host"];The ConfigurationManager shim:
- ✅ Lets BLL/DAL code use
ConfigurationManagerunchanged - ✅ Reads from ASP.NET Core
IConfiguration(appsettings.json) - ✅ Initializes automatically via
AddBlazorWebFormsComponents() - ✅ Supports both flat and nested configuration structures
- ❌ Does not support custom config sections or encryption
Use it for Phase 1 ("Just Make It Compile") migrations. Later, consider migrating to dependency injection for configuration access:
// Phase 2+: Dependency Injection (Better Practice)
public class ProductRepository
{
private readonly IConfiguration _config;
public ProductRepository(IConfiguration config)
{
_config = config;
}
public void Initialize()
{
string connStr = _config.GetConnectionString("DefaultConnection");
// ...
}
}See Service Registration for more on dependency injection patterns in Blazor.