public async Task Run([EventGridTrigger] EventGridEvent eventGridEvent) { var sentinel = _configuration["appsection:sentinel"]; // Invalidate cached key-values before calling TryRefreshAsync _configurationRefresher.SetDirty(TimeSpan.FromSeconds(0)); await _configurationRefresher.TryRefreshAsync(); while (sentinel == _configuration["appsection:sentinel"]) { Console.WriteLine( $"Sentinel value is not updated yet: {_configuration["appsection:sentinel"]}"); await Task.Delay(TimeSpan.FromSeconds(1)); await _configurationRefresher.TryRefreshAsync(); } var message = new Dictionary <string, string> { { "appsection:key1", _configuration["appsection:key1"] }, { "appsection:key2", _configuration.GetValue <string>("appsection:key2") }, { "appsection:sentinel", _configuration["appsection:sentinel"] } }; Console.WriteLine(JsonConvert.SerializeObject(message)); }
public void RefreshTests_TryRefreshAsyncReturnsFalseForAuthenticationFailedException() { IConfigurationRefresher refresher = null; var mockResponse = new Mock <Response>(); var mockClient = new Mock <ConfigurationClient>(MockBehavior.Strict, TestHelpers.CreateMockEndpointString()); mockClient.SetupSequence(c => c.GetConfigurationSettingsAsync(It.IsAny <SettingSelector>(), It.IsAny <CancellationToken>())) .Returns(new MockAsyncPageable(_kvCollection)); var innerException = new AuthenticationFailedException("Authentication failed.") { Source = "Azure.Identity" }; mockClient.SetupSequence(c => c.GetConfigurationSettingAsync("TestKey1", It.IsAny <string>(), It.IsAny <CancellationToken>())) .Returns(Task.FromResult(Response.FromValue(_kvCollection.FirstOrDefault(s => s.Key == "TestKey1"), mockResponse.Object))) .Returns(Task.FromResult(Response.FromValue(_kvCollection.FirstOrDefault(s => s.Key == "TestKey1"), mockResponse.Object))) .Throws(new KeyVaultReferenceException(innerException.Message, innerException)); var config = new ConfigurationBuilder() .AddAzureAppConfiguration(options => { options.Client = mockClient.Object; options.Select("TestKey*"); options.ConfigureRefresh(refreshOptions => { refreshOptions.Register("TestKey1") .SetCacheExpiration(TimeSpan.FromSeconds(1)); }); refresher = options.GetRefresher(); }) .Build(); Assert.Equal("TestValue1", config["TestKey1"]); FirstKeyValue.Value = "newValue"; // Wait for the cache to expire Thread.Sleep(1500); // Second call to GetConfigurationSettingAsync does not throw Assert.True(refresher.TryRefreshAsync().Result); // Wait for the cache to expire Thread.Sleep(1500); // Third call to GetConfigurationSettingAsync throws KeyVaultReferenceException Assert.False(refresher.TryRefreshAsync().Result); }
private static async Task Run(CancellationToken token) { string display = string.Empty; StringBuilder sb = new StringBuilder(); while (!token.IsCancellationRequested) { // Trigger an async refresh for registered configuration settings without wait _ = _refresher.TryRefreshAsync(); sb.AppendLine($"{Configuration["AppName"]} has been configured to run in {Configuration["Language"]}"); sb.AppendLine(); sb.AppendLine(string.Equals(Configuration["Language"], "spanish", StringComparison.OrdinalIgnoreCase) ? "Buenos Dias." : "Good morning"); sb.AppendLine(); sb.AppendLine("Press any key to exit..."); await Task.Delay(1000); if (!sb.ToString().Equals(display)) { display = sb.ToString(); Console.Clear(); Console.Write(display); } sb.Clear(); } }
public void RefreshTests_TryRefreshAsyncReturnsFalseOnRequestFailedException() { IConfigurationRefresher refresher = null; var mockClient = GetMockConfigurationClient(); var config = new ConfigurationBuilder() .AddAzureAppConfiguration(options => { options.Client = mockClient.Object; options.Select("TestKey*"); options.ConfigureRefresh(refreshOptions => { refreshOptions.Register("TestKey1") .SetCacheExpiration(TimeSpan.FromSeconds(1)); }); refresher = options.GetRefresher(); }) .Build(); Assert.Equal("TestValue1", config["TestKey1"]); FirstKeyValue.Value = "newValue"; mockClient.Setup(c => c.GetConfigurationSettingAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <CancellationToken>())) .Throws(new RequestFailedException("Request failed.")); // Wait for the cache to expire Thread.Sleep(1500); bool result = refresher.TryRefreshAsync().Result; Assert.False(result); Assert.NotEqual("newValue", config["TestKey1"]); }
public void RefreshTests_TryRefreshAsyncUpdatesConfigurationAndReturnsTrueOnSuccess() { IConfigurationRefresher refresher = null; var mockClient = GetMockConfigurationClient(); var config = new ConfigurationBuilder() .AddAzureAppConfiguration(options => { options.Client = mockClient.Object; options.Select("TestKey*"); options.ConfigureRefresh(refreshOptions => { refreshOptions.Register("TestKey1") .SetCacheExpiration(TimeSpan.FromSeconds(1)); }); refresher = options.GetRefresher(); }) .Build(); Assert.Equal("TestValue1", config["TestKey1"]); FirstKeyValue.Value = "newValue"; // Wait for the cache to expire Thread.Sleep(1500); bool result = refresher.TryRefreshAsync().Result; Assert.True(result); Assert.Equal("newValue", config["TestKey1"]); }
public async Task OnGet() { _configurationRefresher.SetDirty(TimeSpan.FromSeconds(1)); await Task.Delay(1000); bool success = await _configurationRefresher.TryRefreshAsync(); }
public async Task <IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log) { log.LogInformation("El trigger HTTP con C#, proceso un request."); string keyVaultEntry = "proxymusk"; string messageKeyVault = "keyvault es local"; await _configurationRefresher.TryRefreshAsync(); if (!isLocal) { await _configurationRefresher.RefreshAsync(); messageKeyVault = _configuration[keyVaultEntry]; } bool flag = await _featureManagerSnapshot.IsEnabledAsync("ActivacionMensaje"); string keyName = "TestApp:Settings:Message02"; string message = _configuration[keyName]; if (flag) { GuardaenBD(message, log); } return(message != null ? (ActionResult) new OkObjectResult($"La cadena recuperada desde AppConfig fue '{message}', y el valor desde KeyVault era '{messageKeyVault}' {flag} :)") : new BadRequestObjectResult($"Please create a key-value with the key '{keyName}' in App Configuration, gracias.")); }
public async Task Run([TimerTrigger("0 */1 * * * *")] TimerInfo myTimer, ILogger log) { log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}"); await _configurationRefresher.TryRefreshAsync(); log.LogInformation($"Version {_configuration.GetValue<string>("AzureFunction:Settings:Version")}"); log.LogInformation($"Blob Connection String {_configuration.GetValue<string>("AzureFunction:Settings:BlobConnectionString")}"); log.LogInformation($"B2C Tenant {_configuration.GetValue<string>("AzureFunction:Settings:B2CTenant")}"); }
public async Task <IActionResult> ScheduleJob( [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "schedule")] HttpRequest req, ILogger log) { await _configurationRefresher.TryRefreshAsync(); if (await _featureManagerSnapshot.IsEnabledAsync("RunLoadTests")) { string job = await new StreamReader(req.Body).ReadToEndAsync(); await _client.SendMessageAsync(job); } return((IActionResult) new OkResult()); }
public async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log) { log.LogInformation("C# HTTP trigger function processed a request."); await _configurationRefresher.TryRefreshAsync(); string keyName = "TestApp:Settings:Message"; string message = _configuration[keyName]; return(message != null ? (ActionResult) new OkObjectResult(message) : new BadRequestObjectResult($"Please create a key-value with the key '{keyName}' in App Configuration.")); }
public async Task <string> CheckOtherShipsFlag([ActivityTrigger] object obj) { await _refresher.TryRefreshAsync(); var shipFlag = "The West India Company"; var usePirateShip = await this._featureManager.IsEnabledAsync("pirate-flag"); if (usePirateShip) { shipFlag = "Pirate"; } return(shipFlag); }
public async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req, ILogger log) { log.LogInformation("C# HTTP trigger function processed a request."); await _configurationRefresher.TryRefreshAsync(); string message = await _featureManager.IsEnabledAsync("Beta") ? "The Feature Flag 'Beta' is turned ON" : "The Feature Flag 'Beta' is turned OFF"; return((ActionResult) new OkObjectResult(message)); }
public async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req, ExecutionContext context, ILogger log) { log.LogInformation("C# HTTP trigger function processed a request."); await _configurationRefresher.TryRefreshAsync(); string loaderIOVerificationToken = _configuration["EnterpriseServerless:LoaderIO_VerificationToken"]; string responseMessage = string.IsNullOrEmpty(loaderIOVerificationToken) ? "This HTTP triggered function executed successfully, however its missing the verification token." : loaderIOVerificationToken; return(new OkObjectResult(responseMessage)); }
public async Task <IActionResult> RunAsync( [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log) { await _refresher.TryRefreshAsync(); var shipFlag = "The India Company"; var usePirateShip = await this._featureManager.IsEnabledAsync("pirate-flag"); if (usePirateShip) { shipFlag = "Pirate"; } return((ActionResult) new OkObjectResult($"The ship has a {shipFlag} flag ")); }
public void OverwriteLoggerFactory() { IConfigurationRefresher refresher = null; var mockClient = GetMockConfigurationClient(); mockClient.Setup(c => c.GetConfigurationSettingAsync(It.IsAny <ConfigurationSetting>(), It.IsAny <bool>(), It.IsAny <CancellationToken>())) .Throws(new RequestFailedException(403, "Forbidden")); var mockLogger1 = new Mock <ILogger>(); var mockLoggerFactory1 = new Mock <ILoggerFactory>(); mockLoggerFactory1.Setup(mlf => mlf.CreateLogger(LoggingConstants.AppConfigRefreshLogCategory)).Returns(mockLogger1.Object); var mockLogger2 = new Mock <ILogger>(); var mockLoggerFactory2 = new Mock <ILoggerFactory>(); mockLoggerFactory2.Setup(mlf => mlf.CreateLogger(LoggingConstants.AppConfigRefreshLogCategory)).Returns(mockLogger2.Object); var config = new ConfigurationBuilder() .AddAzureAppConfiguration(options => { options.Client = mockClient.Object; options.ConfigureRefresh(refreshOptions => { refreshOptions.Register("TestKey1", "label") .SetCacheExpiration(CacheExpirationTime); }); refresher = options.GetRefresher(); }) .Build(); Assert.Equal("TestValue1", config["TestKey1"]); FirstKeyValue.Value = "newValue1"; // Set LoggerFactory refresher.LoggerFactory = mockLoggerFactory1.Object; // Overwrite LoggerFactory refresher.LoggerFactory = mockLoggerFactory2.Object; Thread.Sleep(CacheExpirationTime); refresher.TryRefreshAsync().Wait(); Assert.NotEqual("newValue1", config["TestKey1"]); Assert.True(ValidateLoggedError(mockLogger2, LoggingConstants.RefreshFailedDueToAuthenticationError)); }
public async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, ILogger log) { log.LogInformation("C# HTTP trigger function processed a request."); // Signal to refresh the configuration if the registered key(s) is modified. // This will be a no-op if the cache expiration time window is not reached. // The configuration is refreshed asynchronously without blocking the execution of the current function. _ = _configurationRefresher.TryRefreshAsync(); string message = _settings.Message; return(message != null ? (ActionResult) new OkObjectResult(message) : new BadRequestObjectResult($"Please create a key-value with the key 'TestApp:Settings:Message' in Azure App Configuration.")); }
public async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, ILogger log) { log.LogInformation("C# HTTP trigger function processed a request."); // Signal to refresh the feature flags from Azure App Configuration. // This will be a no-op if the cache expiration time window is not reached. // Remove the 'await' operator if it's preferred to refresh without blocking. await _configurationRefresher.TryRefreshAsync(); string featureName = "Beta"; bool featureEnalbed = await _featureManagerSnapshot.IsEnabledAsync(featureName); return(featureEnalbed ? (ActionResult) new OkObjectResult($"{featureName} feature is On") : new BadRequestObjectResult($"{featureName} feature is Off (or the feature flag '{featureName}' is not present in Azure App Configuration).")); }
public void ValidateOperationCanceledExceptionLoggedDuringRefresh() { IConfigurationRefresher refresher = null; var mockClient = GetMockConfigurationClient(); var mockLogger = new Mock <ILogger>(); var mockLoggerFactory = new Mock <ILoggerFactory>(); mockLoggerFactory.Setup(mlf => mlf.CreateLogger(LoggingConstants.AppConfigRefreshLogCategory)).Returns(mockLogger.Object); var config = new ConfigurationBuilder() .AddAzureAppConfiguration(options => { options.Client = mockClient.Object; options.ConfigureRefresh(refreshOptions => { refreshOptions.Register("TestKey1", "label") .SetCacheExpiration(CacheExpirationTime); }); refresher = options.GetRefresher(); }) .Build(); Assert.Equal("TestValue1", config["TestKey1"]); FirstKeyValue.Value = "newValue1"; Thread.Sleep(CacheExpirationTime); refresher.LoggerFactory = mockLoggerFactory.Object; using var cancellationSource = new CancellationTokenSource(); cancellationSource.CancelAfter(TimeSpan.Zero); refresher.TryRefreshAsync(cancellationSource.Token).Wait(); Assert.NotEqual("newValue1", config["TestKey1"]); Assert.True(ValidateLoggedError(mockLogger, LoggingConstants.RefreshCanceledError)); }
public void ValidateKeyVaultExceptionLoggedDuringRefresh() { IConfigurationRefresher refresher = null; TimeSpan cacheExpirationTime = TimeSpan.FromSeconds(1); // Mock ConfigurationClient var mockResponse = new Mock <Response>(); var mockClient = new Mock <ConfigurationClient>(MockBehavior.Strict, TestHelpers.CreateMockEndpointString()); Response <ConfigurationSetting> GetTestKey(string key, string label, CancellationToken cancellationToken) { return(Response.FromValue(TestHelpers.CloneSetting(sentinelKv), mockResponse.Object)); } Response <ConfigurationSetting> GetIfChanged(ConfigurationSetting setting, bool onlyIfChanged, CancellationToken cancellationToken) { var unchanged = sentinelKv.Key == setting.Key && sentinelKv.Label == setting.Label && sentinelKv.Value == setting.Value; var response = new MockResponse(unchanged ? 304 : 200); return(Response.FromValue(sentinelKv, response)); } // No KVR during startup; return KVR during refresh operation to see error because ConfigureKeyVault is missing mockClient.SetupSequence(c => c.GetConfigurationSettingsAsync(It.IsAny <SettingSelector>(), It.IsAny <CancellationToken>())) .Returns(new MockAsyncPageable(_kvCollection.Select(setting => TestHelpers.CloneSetting(setting)).ToList())) .Returns(new MockAsyncPageable(new List <ConfigurationSetting> { _kvr })); mockClient.Setup(c => c.GetConfigurationSettingAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <CancellationToken>())) .ReturnsAsync((Func <string, string, CancellationToken, Response <ConfigurationSetting> >)GetTestKey); mockClient.Setup(c => c.GetConfigurationSettingAsync(It.IsAny <ConfigurationSetting>(), It.IsAny <bool>(), It.IsAny <CancellationToken>())) .ReturnsAsync((Func <ConfigurationSetting, bool, CancellationToken, Response <ConfigurationSetting> >)GetIfChanged); // Mock ILogger and ILoggerFactory var mockLogger = new Mock <ILogger>(); var mockLoggerFactory = new Mock <ILoggerFactory>(); mockLoggerFactory.Setup(mlf => mlf.CreateLogger(LoggingConstants.AppConfigRefreshLogCategory)).Returns(mockLogger.Object); var config = new ConfigurationBuilder() .AddAzureAppConfiguration(options => { options.Client = mockClient.Object; options.ConfigureRefresh(refreshOptions => { refreshOptions.Register("SentinelKey", refreshAll: true) .SetCacheExpiration(CacheExpirationTime); }); refresher = options.GetRefresher(); }) .Build(); Assert.Equal("SentinelValue", config["SentinelKey"]); // Update sentinel key-value to trigger refreshAll operation sentinelKv.Value = "UpdatedSentinelValue"; Thread.Sleep(CacheExpirationTime); refresher.LoggerFactory = mockLoggerFactory.Object; refresher.TryRefreshAsync().Wait(); Assert.True(ValidateLoggedError(mockLogger, LoggingConstants.RefreshFailedDueToKeyVaultError)); }
public void RefreshTests_SentinelKeyNotUpdatedOnRefreshAllFailure() { var serviceCollection = new List <ConfigurationSetting>(_kvCollection); var mockResponse = new Mock <Response>(); var mockClient = new Mock <ConfigurationClient>(MockBehavior.Strict, TestHelpers.CreateMockEndpointString()); Response <ConfigurationSetting> GetIfChanged(ConfigurationSetting setting, bool onlyIfChanged, CancellationToken cancellationToken) { var newSetting = serviceCollection.FirstOrDefault(s => s.Key == setting.Key); var unchanged = (newSetting.Key == setting.Key && newSetting.Label == setting.Label && newSetting.Value == setting.Value); var response = new MockResponse(unchanged ? 304 : 200); return(Response.FromValue(newSetting, response)); } mockClient.SetupSequence(c => c.GetConfigurationSettingsAsync(It.IsAny <SettingSelector>(), It.IsAny <CancellationToken>())) .Returns(new MockAsyncPageable(serviceCollection.Select(setting => TestHelpers.CloneSetting(setting)).ToList())) .Throws(new RequestFailedException(429, "Too many requests")) .Returns(new MockAsyncPageable(serviceCollection.Select(setting => { setting.Value = "newValue"; return(TestHelpers.CloneSetting(setting)); }).ToList())); mockClient.Setup(c => c.GetConfigurationSettingAsync(It.IsAny <ConfigurationSetting>(), It.IsAny <bool>(), It.IsAny <CancellationToken>())) .ReturnsAsync((Func <ConfigurationSetting, bool, CancellationToken, Response <ConfigurationSetting> >)GetIfChanged); IConfigurationRefresher refresher = null; var config = new ConfigurationBuilder() .AddAzureAppConfiguration(options => { options.Client = mockClient.Object; options.Select("TestKey*", "label"); options.ConfigureRefresh(refreshOptions => { refreshOptions.Register("TestKey1", "label", refreshAll: true) .SetCacheExpiration(TimeSpan.FromSeconds(1)); }); refresher = options.GetRefresher(); }) .Build(); Assert.Equal("TestValue1", config["TestKey1"]); Assert.Equal("TestValue2", config["TestKey2"]); Assert.Equal("TestValue3", config["TestKey3"]); serviceCollection.ForEach(kv => kv.Value = "newValue"); // Wait for the cache to expire Thread.Sleep(1500); bool firstRefreshResult = refresher.TryRefreshAsync().Result; Assert.False(firstRefreshResult); Assert.Equal("TestValue1", config["TestKey1"]); Assert.Equal("TestValue2", config["TestKey2"]); Assert.Equal("TestValue3", config["TestKey3"]); // Wait for the cache to expire Thread.Sleep(1500); bool secondRefreshResult = refresher.TryRefreshAsync().Result; Assert.True(secondRefreshResult); Assert.Equal("newValue", config["TestKey1"]); Assert.Equal("newValue", config["TestKey2"]); Assert.Equal("newValue", config["TestKey3"]); }
public ApplicationConfigService(IConfiguration configuration, IConfigurationRefresherProvider refresherProvider) { _config = configuration; _configRefresher = refresherProvider.Refreshers.First(); _configRefresher.TryRefreshAsync(); }