/// <summary> /// Enables Azure App Configuration feature flags to be parsed and transformed into feature management configuration. /// </summary> /// <param name="configure">A callback used to configure feature flag options.</param> public AzureAppConfigurationOptions UseFeatureFlags(Action <FeatureFlagOptions> configure = null) { FeatureFlagOptions options = new FeatureFlagOptions(); configure?.Invoke(options); if (options.CacheExpirationTime < MinimumFeatureFlagsCacheExpiration) { throw new ArgumentOutOfRangeException(nameof(options.CacheExpirationTime), options.CacheExpirationTime.TotalMilliseconds, string.Format(Constants.ErrorMessages.CacheExpirationTimeTooShort, MinimumFeatureFlagsCacheExpiration.TotalMilliseconds)); } if (!(_kvSelectors.Any(selector => selector.KeyFilter.StartsWith(FeatureManagementConstants.FeatureFlagMarker) && selector.LabelFilter.Equals(options.Label)))) { Select(FeatureManagementConstants.FeatureFlagMarker + "*", options.Label); } if (!_adapters.Any(a => a is FeatureManagementKeyValueAdapter)) { _adapters.Add(new FeatureManagementKeyValueAdapter()); } if (!_multiKeyWatchers.Any(kw => kw.Key.Equals(FeatureManagementConstants.FeatureFlagMarker))) { _multiKeyWatchers.Add(new KeyValueWatcher { Key = FeatureManagementConstants.FeatureFlagMarker, Label = options.Label, CacheExpirationTime = options.CacheExpirationTime }); } return(this); }
public FactsBase() { _storage = new Mock <IFeatureFlagStorageService>(); _telemetry = new Mock <IFeatureFlagTelemetryService>(); _options = new FeatureFlagOptions(); _target = new FeatureFlagCacheService( _storage.Object, _options, _telemetry.Object, Mock.Of <ILogger <FeatureFlagCacheService> >()); _latestFlags = FeatureFlagStateBuilder .Create() .WithFeature("Foo", FeatureStatus.Enabled) .Build(); _stalenessMetrics = new List <TimeSpan>(); _telemetry .Setup(t => t.TrackFeatureFlagStaleness(It.IsAny <TimeSpan>())) .Callback((TimeSpan staleness) => { _stalenessMetrics.Add(staleness); }); }
public Startup(IConfiguration configuration) { Configuration = configuration; options = new FeatureFlagOptions() .UseInMemoryFeatureProvider(); // .UseCachedSqlFeatureProvider(Configuration.GetConnectionString("localDb")); }
public Startup(IConfiguration configuration) { Configuration = configuration; _options = new FeatureFlagOptions().UseInMemoryFeatureProvider(); }
public static IConfigurationBuilder AddAzureAppConfiguration( this IConfigurationBuilder configurationBuilder, string currentEnvironment, Action <AzureAppConfigConnectOptions, FiltersOptions, FeatureFlagOptions>?configureConnect = default, string sectionName = Sections.AzureAppConfig, bool throwExceptionOnStoreNotFound = false, string?envSectionName = null) { var configuration = configurationBuilder.Build(); return(configurationBuilder.AddAzureAppConfiguration( options => { var env = new Environments(); if (!string.IsNullOrEmpty(envSectionName)) { env.Clear(); configuration.Bind(envSectionName, env); } // create connection options var connectOptions = new AzureAppConfigConnectOptions(); configuration.Bind(sectionName, connectOptions); var filtersOptions = new FiltersOptions(); configuration.Bind($"{sectionName}:Filters", filtersOptions); var featuresOptions = new FeatureFlagOptions(); configuration.Bind($"{sectionName}:Features", featuresOptions); configureConnect?.Invoke(connectOptions, filtersOptions, featuresOptions); // configure features options.UseFeatureFlags(fo => { fo.CacheExpirationInterval = featuresOptions.CacheExpirationInterval; if (!string.IsNullOrEmpty(featuresOptions.Label)) { fo.Label = env[featuresOptions.Label]; } }); if (!string.IsNullOrEmpty(connectOptions.ConnectionString)) { options.Connect(connectOptions.ConnectionString); } else if (connectOptions.Endpoint != null && string.IsNullOrEmpty(connectOptions.ConnectionString)) { var credentials = new DefaultAzureCredential(); options.Connect(connectOptions.Endpoint, credentials); } options.ConfigureClientOptions(clientOptions => clientOptions.Retry.MaxRetries = connectOptions.MaxRetries); foreach (var section in filtersOptions.Sections) { // Load configuration values with no label, which means all of the configurations that are not specific to // Environment options.Select(section); // Override with any configuration values specific to current hosting env options.Select(section, env[currentEnvironment]); } foreach (var section in filtersOptions.RefresSections) { options.ConfigureRefresh(refresh => { refresh.Register(section, refreshAll: true); refresh.Register(section, env[currentEnvironment], refreshAll: true); refresh.SetCacheExpiration(filtersOptions.CacheExpirationTime); }); } }, throwExceptionOnStoreNotFound)); }