Most likely you’re seeing old values because of labels or the provider cache/refresh behavior — not because the service itself is stale (you already confirmed az appconfig kv list shows the new keys). Two things to check/fix
1. Label filtering
By default the .NET provider loads only key-values that have no label. If the new keys you added have a label (for example dev, prod, or even an accidental label), the provider will not return them unless you explicitly select that label (or select all labels).
If you want to load keys regardless of label:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.AzureAppConfiguration;
using Microsoft.Extensions.Configuration.AzureAppConfiguration.Extensions;
var builder = new ConfigurationBuilder();
builder.AddAzureAppConfiguration(options =>
{
options.Connect(connectionString)
.Select(KeyFilter.Any, LabelFilter.Any); // <-- load keys across all labels
});
var config = builder.Build();
Or specify the exact label you use:
.Select("MyApp:*", "dev") // load keys with label "dev"
Docs: the provider defaults to loading only unlabeled keys; use LabelFilter.Any or pass your label via Select.
2. Provider snapshot / cache
The App Configuration .NET provider loads a snapshot and caches values. Adding keys in the portal does not magically push them into an already-running process. To pick up runtime changes you must either:
restart the app (simple), or
incorporate the provider’s refresh capability and call TryRefreshAsync/IConfigurationRefresher (recommended for long-running apps).
Example pattern (console / background service):
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.AzureAppConfiguration;
using Microsoft.Extensions.Configuration.AzureAppConfiguration.Extensions;
IConfigurationRefresher refresher = null;
var builder = new ConfigurationBuilder();
builder.AddAzureAppConfiguration(options =>
{
options.Connect(connectionString)
.Select(KeyFilter.Any, LabelFilter.Any) // or your label
.ConfigureRefresh(refresh =>
{
// register a sentinel key or a key to watch
refresh.Register("SentinelKey", LabelFilter.Null, refreshAll: true)
.SetCacheExpiration(TimeSpan.FromSeconds(30)); // how often provider will poll
});
refresher = options.GetRefresher(); // keep a reference to trigger refreshes
});
var config = builder.Build();
// Later, when your app is active, try to refresh:
await refresher.TryRefreshAsync(); // will pull latest values if sentinel changed (or expired)
Notes:
-
ConfigureRefreshtells the provider what to monitor (often a "sentinel" key) and how the cache behaves; it doesn’t automatically refresh on every read. You must callTryRefreshAsync()(or wire refresh into middleware, a timer, or request handling).
If you want immediate pickup without sentinel logic, restart the app — that rebuilds the provider and loads the latest values.
- If you call
TryRefreshAsync()and nothing changes, you might need toSetDirty()/ register proper sentinel keys so the provider knows to invalidate cache. (Some scenarios requireSetDirtyto force cache invalidation.)