Microsoft.FeatureManagement provides standardized APIs for enabling feature flags within applications. Utilize this library to secure a consistent experience when developing applications that use patterns such as beta access, rollout, dark deployments, and more.
A developer had an issue. After refresh they were getting:
Object reference not set to an instance of an object
at Microsoft.FeatureManagement.FeatureManager.\d__10.MoveNext()
After trying to recreate the issue, I found one way. The steps are as follows:
Call FeatureManager.GetFeatureNamesAsync().
Iterate the first item in the AsyncEnumerable. ( This means, ConfigurationFeatureDefinitionProvider.GetAllFeatureDefinitionsAsync will iterate once, meaning it will grab a list of all IConfigurationSections defined within FeatureManagement, but only iterate the first one )
Remove a flag from the Configuration
Refresh configuration
Call IsEnabledAsync("RemovedFlag") or iterate through a full GetFeatureNamesAsync. This fills the cache with "null".
Continue iterating the first AsyncEnumerable.
In short- the cache gets busted when the refresh happens, but the old AsyncEnumerable is not updated. It expects the IConfigurationSection it saw before iterating to still exist.
Visible Changes
This fix is in two places-
The AsyncEnumerable in ConfigurationFeatureDefinitionProvider will check for null iteration- since iterations can be as slow as the developer wants. If the same situation happens- there might be a null in the cache, but we won't return it.
Why this PR?
A developer had an issue. After refresh they were getting:
After trying to recreate the issue, I found one way. The steps are as follows:
FeatureManager.GetFeatureNamesAsync()
.ConfigurationFeatureDefinitionProvider.GetAllFeatureDefinitionsAsync
will iterate once, meaning it will grab a list of allIConfigurationSections
defined within FeatureManagement, but only iterate the first one )IsEnabledAsync("RemovedFlag")
or iterate through a fullGetFeatureNamesAsync
. This fills the cache with "null".In short- the cache gets busted when the refresh happens, but the old AsyncEnumerable is not updated. It expects the IConfigurationSection it saw before iterating to still exist.
Visible Changes
This fix is in two places-
AsyncEnumerable
inConfigurationFeatureDefinitionProvider
will check for null iteration- since iterations can be as slow as the developer wants. If the same situation happens- there might be a null in the cache, but we won't return it.