Skip to content
Back to Blog
1 min read

Centralized Configuration Management with Azure App Configuration

Why Azure App Configuration?

Traditional configuration approaches using appsettings.json or environment variables have limitations:

  • No central management
  • Requires redeployment for changes
  • Difficult to maintain consistency across services
  • No built-in feature flag support

Azure App Configuration solves these problems with:

  • Centralized configuration store
  • Real-time configuration updates
  • Feature flag management
  • Key Vault integration for secrets
  • Configuration snapshots and versioning

Setting Up Azure App Configuration

# Create App Configuration store
az appconfig create \
    --name myappconfig \
    --resource-group myResourceGroup \
    --location eastus \
    --sku Standard

# Add configuration values
az appconfig kv set \
    --name myappconfig \
    --key "Settings:ServiceEndpoint" \
    --value "https://api.example.com" \
    --yes

az appconfig kv set \
    --name myappconfig \
    --key "Settings:MaxRetries" \
    --value "3" \
    --yes

# Add labeled configurations for different environments
az appconfig kv set \
    --name myappconfig \
    --key "Settings:ServiceEndpoint" \
    --value "https://api-dev.example.com" \
    --label "Development" \
    --yes

az appconfig kv set \
    --name myappconfig \
    --key "Settings:ServiceEndpoint" \
    --value "https://api-prod.example.com" \
    --label "Production" \
    --yes

.NET Core Integration

Add the required packages:

dotnet add package Microsoft.Azure.AppConfiguration.AspNetCore
dotnet add package Microsoft.FeatureManagement.AspNetCore

Configure in Program.cs:

// Program.cs
using Microsoft.FeatureManagement;

var builder = WebApplication.CreateBuilder(args);

// Add Azure App Configuration
var connectionString = builder.Configuration.GetConnectionString("AppConfig");

builder.Configuration.AddAzureAppConfiguration(options =>
{
    options.Connect(connectionString)
        // Load all keys with no label
        .Select(KeyFilter.Any, LabelFilter.Null)
        // Load keys for current environment
        .Select(KeyFilter.Any, builder.Environment.EnvironmentName)
        // Enable dynamic configuration refresh
        .ConfigureRefresh(refresh =>
        {
            refresh.Register("Settings:Sentinel", refreshAll: true)
                   .SetCacheExpiration(TimeSpan.FromSeconds(30));
        })
        // Load feature flags
        .UseFeatureFlags(featureFlags =>
        {
            featureFlags.CacheExpirationInterval = TimeSpan.FromMinutes(5);
        });
});

builder.Services.AddAzureAppConfiguration();
builder.Services.AddFeatureManagement();

var app = builder.Build();

// Enable dynamic configuration
app.UseAzureAppConfiguration();

app.MapGet("/", () => "Hello World!");

app.Run();

Configuration model:

// Settings.cs
public class Settings
{
    public string ServiceEndpoint { get; set; }
    public int MaxRetries { get; set; }
    public TimeSpan Timeout { get; set; }
}

// Configure in startup
builder.Services.Configure<Settings>(
    builder.Configuration.GetSection("Settings"));

Using configuration in a service:

// MyService.cs
public class MyService
{
    private readonly IOptionsSnapshot<Settings> _settings;
    private readonly ILogger<MyService> _logger;

    public MyService(IOptionsSnapshot<Settings> settings, ILogger<MyService> logger)
    {
        _settings = settings;
        _logger = logger;
    }

    public async Task<string> CallExternalServiceAsync()
    {
        var endpoint = _settings.Value.ServiceEndpoint;
        var maxRetries = _settings.Value.MaxRetries;

        _logger.LogInformation("Calling {Endpoint} with {MaxRetries} retries",
            endpoint, maxRetries);

        // Your implementation here
        using var client = new HttpClient();
        var response = await client.GetStringAsync(endpoint);
        return response;
    }
}

Feature Flags

Create feature flags in App Configuration:

# Create a simple feature flag
az appconfig feature set \
    --name myappconfig \
    --feature Beta \
    --yes

# Create a feature flag with conditions
az appconfig feature set \
    --name myappconfig \
    --feature PremiumFeature \
    --yes

az appconfig feature filter add \
    --name myappconfig \
    --feature PremiumFeature \
    --filter-name Microsoft.Percentage \
    --filter-parameters Value=50

Using feature flags in code:

// Controllers/HomeController.cs
using Microsoft.FeatureManagement;
using Microsoft.FeatureManagement.Mvc;

[ApiController]
[Route("[controller]")]
public class HomeController : ControllerBase
{
    private readonly IFeatureManager _featureManager;

    public HomeController(IFeatureManager featureManager)
    {
        _featureManager = featureManager;
    }

    [HttpGet]
    public async Task<IActionResult> Get()
    {
        if (await _featureManager.IsEnabledAsync("Beta"))
        {
            return Ok("Welcome to the beta experience!");
        }

        return Ok("Welcome!");
    }

    // Use attribute-based feature flag
    [FeatureGate("PremiumFeature")]
    [HttpGet("premium")]
    public IActionResult GetPremium()
    {
        return Ok("Premium content here!");
    }
}

Custom feature filter:

// UserTargetingFilter.cs
using Microsoft.FeatureManagement;

[FilterAlias("UserTargeting")]
public class UserTargetingFilter : IFeatureFilter
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public UserTargetingFilter(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context)
    {
        var settings = context.Parameters.Get<UserTargetingSettings>();
        var user = _httpContextAccessor.HttpContext?.User;

        if (user?.Identity?.IsAuthenticated == true)
        {
            var userId = user.FindFirst("sub")?.Value;
            return Task.FromResult(settings.AllowedUsers.Contains(userId));
        }

        return Task.FromResult(false);
    }
}

public class UserTargetingSettings
{
    public List<string> AllowedUsers { get; set; } = new();
}

// Register in Program.cs
builder.Services.AddFeatureManagement()
    .AddFeatureFilter<UserTargetingFilter>();

Key Vault References

Store secrets in Key Vault and reference them from App Configuration:

# Create Key Vault and secret
az keyvault create \
    --name mykeyvault \
    --resource-group myResourceGroup \
    --location eastus

az keyvault secret set \
    --vault-name mykeyvault \
    --name "DatabasePassword" \
    --value "super-secret-password"

# Create Key Vault reference in App Configuration
az appconfig kv set-keyvault \
    --name myappconfig \
    --key "ConnectionStrings:Database:Password" \
    --secret-identifier "https://mykeyvault.vault.azure.net/secrets/DatabasePassword" \
    --yes

Configure the application to resolve Key Vault references:

builder.Configuration.AddAzureAppConfiguration(options =>
{
    options.Connect(connectionString)
        .ConfigureKeyVault(kv =>
        {
            kv.SetCredential(new DefaultAzureCredential());
        });
});

Configuration Snapshots

Create immutable snapshots for deployment consistency:

# Create a snapshot
az appconfig snapshot create \
    --name myappconfig \
    --snapshot-name "release-v1.0.0" \
    --filters '{\"key\":\"Settings:*\",\"label\":\"Production\"}'

# List snapshots
az appconfig snapshot list --name myappconfig

# Use snapshot in application
builder.Configuration.AddAzureAppConfiguration(options =>
{
    options.Connect(connectionString)
        .SelectSnapshot("release-v1.0.0");
});

Conclusion

Azure App Configuration simplifies configuration management for modern applications. By centralizing settings and feature flags, you gain:

  • Single source of truth for configuration
  • Dynamic updates without redeployment
  • Environment-specific settings with labels
  • Secure secret management through Key Vault integration
  • Powerful feature flag capabilities for progressive rollouts

Start with basic key-value storage and gradually adopt feature flags and Key Vault integration as your needs grow.

Michael John Pena

Michael John Pena

Data & AI Director and Microsoft MVP based in Sydney. Writing about Microsoft Fabric, Azure, data engineering, and AI.