@@ -22,8 +22,9 @@ public sealed class ConfigurationFeatureDefinitionProvider : IFeatureDefinitionP
2222 //
2323 // IFeatureDefinitionProviderCacheable interface is only used to mark this provider as cacheable. This allows our test suite's
2424 // provider to be marked for caching as well.
25-
2625 private readonly IConfiguration _configuration ;
26+ private IEnumerable < IConfigurationSection > _dotnetFeatureDefinitionSections ;
27+ private IEnumerable < IConfigurationSection > _microsoftFeatureDefinitionSections ;
2728 private readonly ConcurrentDictionary < string , Task < FeatureDefinition > > _definitions ;
2829 private IDisposable _changeSubscription ;
2930 private int _stale = 0 ;
@@ -48,6 +49,10 @@ public ConfigurationFeatureDefinitionProvider(IConfiguration configuration)
4849 {
4950 return Task . FromResult ( GetMicrosoftSchemaFeatureDefinition ( featureName ) ?? GetDotnetSchemaFeatureDefinition ( featureName ) ) ;
5051 } ;
52+
53+ _dotnetFeatureDefinitionSections = GetDotnetFeatureDefinitionSections ( ) ;
54+
55+ _microsoftFeatureDefinitionSections = GetMicrosoftFeatureDefinitionSections ( ) ;
5156 }
5257
5358 /// <summary>
@@ -90,6 +95,10 @@ public Task<FeatureDefinition> GetFeatureDefinitionAsync(string featureName)
9095 if ( Interlocked . Exchange ( ref _stale , 0 ) != 0 )
9196 {
9297 _definitions . Clear ( ) ;
98+
99+ _dotnetFeatureDefinitionSections = GetDotnetFeatureDefinitionSections ( ) ;
100+
101+ _microsoftFeatureDefinitionSections = GetMicrosoftFeatureDefinitionSections ( ) ;
93102 }
94103
95104 return _definitions . GetOrAdd ( featureName , _getFeatureDefinitionFunc ) ;
@@ -109,11 +118,13 @@ public async IAsyncEnumerable<FeatureDefinition> GetAllFeatureDefinitionsAsync()
109118 if ( Interlocked . Exchange ( ref _stale , 0 ) != 0 )
110119 {
111120 _definitions . Clear ( ) ;
112- }
113121
114- IEnumerable < IConfigurationSection > microsoftFeatureDefinitionSections = GetMicrosoftFeatureDefinitionSections ( ) ;
122+ _dotnetFeatureDefinitionSections = GetDotnetFeatureDefinitionSections ( ) ;
123+
124+ _microsoftFeatureDefinitionSections = GetMicrosoftFeatureDefinitionSections ( ) ;
125+ }
115126
116- foreach ( IConfigurationSection featureSection in microsoftFeatureDefinitionSections )
127+ foreach ( IConfigurationSection featureSection in _microsoftFeatureDefinitionSections )
117128 {
118129 string featureName = featureSection [ MicrosoftFeatureManagementFields . Id ] ;
119130
@@ -132,9 +143,7 @@ public async IAsyncEnumerable<FeatureDefinition> GetAllFeatureDefinitionsAsync()
132143 }
133144 }
134145
135- IEnumerable < IConfigurationSection > dotnetFeatureDefinitionSections = GetDotnetFeatureDefinitionSections ( ) ;
136-
137- foreach ( IConfigurationSection featureSection in dotnetFeatureDefinitionSections )
146+ foreach ( IConfigurationSection featureSection in _dotnetFeatureDefinitionSections )
138147 {
139148 string featureName = featureSection . Key ;
140149
@@ -156,9 +165,7 @@ public async IAsyncEnumerable<FeatureDefinition> GetAllFeatureDefinitionsAsync()
156165
157166 private FeatureDefinition GetDotnetSchemaFeatureDefinition ( string featureName )
158167 {
159- IEnumerable < IConfigurationSection > dotnetFeatureDefinitionSections = GetDotnetFeatureDefinitionSections ( ) ;
160-
161- IConfigurationSection dotnetFeatureDefinitionConfiguration = dotnetFeatureDefinitionSections
168+ IConfigurationSection dotnetFeatureDefinitionConfiguration = _dotnetFeatureDefinitionSections
162169 . FirstOrDefault ( section =>
163170 string . Equals ( section . Key , featureName , StringComparison . OrdinalIgnoreCase ) ) ;
164171
@@ -172,9 +179,7 @@ private FeatureDefinition GetDotnetSchemaFeatureDefinition(string featureName)
172179
173180 private FeatureDefinition GetMicrosoftSchemaFeatureDefinition ( string featureName )
174181 {
175- IEnumerable < IConfigurationSection > microsoftFeatureDefinitionSections = GetMicrosoftFeatureDefinitionSections ( ) ;
176-
177- IConfigurationSection microsoftFeatureDefinitionConfiguration = microsoftFeatureDefinitionSections
182+ IConfigurationSection microsoftFeatureDefinitionConfiguration = _microsoftFeatureDefinitionSections
178183 . LastOrDefault ( section =>
179184 string . Equals ( section [ MicrosoftFeatureManagementFields . Id ] , featureName , StringComparison . OrdinalIgnoreCase ) ) ;
180185
@@ -211,9 +216,55 @@ private IEnumerable<IConfigurationSection> GetDotnetFeatureDefinitionSections()
211216
212217 private IEnumerable < IConfigurationSection > GetMicrosoftFeatureDefinitionSections ( )
213218 {
214- return _configuration . GetSection ( MicrosoftFeatureManagementFields . FeatureManagementSectionName )
215- . GetSection ( MicrosoftFeatureManagementFields . FeatureFlagsSectionName )
216- . GetChildren ( ) ;
219+ var featureDefinitionSections = new List < IConfigurationSection > ( ) ;
220+
221+ FindFeatureFlags ( _configuration , featureDefinitionSections ) ;
222+
223+ return featureDefinitionSections ;
224+ }
225+
226+ private void FindFeatureFlags ( IConfiguration configuration , List < IConfigurationSection > featureDefinitionSections )
227+ {
228+ if ( ! ( configuration is IConfigurationRoot configurationRoot ) ||
229+ configurationRoot . Providers . Any ( provider =>
230+ ! ( provider is ConfigurationProvider ) && ! ( provider is ChainedConfigurationProvider ) ) )
231+ {
232+ IConfigurationSection featureFlagsSection = configuration
233+ . GetSection ( MicrosoftFeatureManagementFields . FeatureManagementSectionName )
234+ . GetSection ( MicrosoftFeatureManagementFields . FeatureFlagsSectionName ) ;
235+
236+ if ( featureFlagsSection . Exists ( ) )
237+ {
238+ featureDefinitionSections . AddRange ( featureFlagsSection . GetChildren ( ) ) ;
239+ }
240+
241+ return ;
242+ }
243+
244+ foreach ( IConfigurationProvider provider in configurationRoot . Providers )
245+ {
246+ if ( provider is ConfigurationProvider configurationProvider )
247+ {
248+ //
249+ // Cannot use the original provider directly as its reload token is subscribed
250+ var onDemandConfigurationProvider = new OnDemandConfigurationProvider ( configurationProvider ) ;
251+
252+ var onDemandConfigurationRoot = new ConfigurationRoot ( new [ ] { onDemandConfigurationProvider } ) ;
253+
254+ IConfigurationSection featureFlagsSection = onDemandConfigurationRoot
255+ . GetSection ( MicrosoftFeatureManagementFields . FeatureManagementSectionName )
256+ . GetSection ( MicrosoftFeatureManagementFields . FeatureFlagsSectionName ) ;
257+
258+ if ( featureFlagsSection . Exists ( ) )
259+ {
260+ featureDefinitionSections . AddRange ( featureFlagsSection . GetChildren ( ) ) ;
261+ }
262+ }
263+ else if ( provider is ChainedConfigurationProvider chainedProvider )
264+ {
265+ FindFeatureFlags ( chainedProvider . Configuration , featureDefinitionSections ) ;
266+ }
267+ }
217268 }
218269
219270 private FeatureDefinition ParseDotnetSchemaFeatureDefinition ( IConfigurationSection configurationSection )
0 commit comments