Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions examples/ConfigStoreDemo/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,6 @@ public static IWebHost BuildWebHost(string[] args)
// 3. Set up the provider to listen for changes to the background color key-value in Azure App Configuration

var settings = config.AddJsonFile("appsettings.json").Build();

if (string.IsNullOrEmpty(settings["connection_string"]))
{
throw new InvalidOperationException(
"Connection string not found. " +
"Please set the 'connection_string' in appsettings.json.");
}

config.AddAzureAppConfiguration(options =>
{
options.Connect(settings["connection_string"])
Expand Down
5 changes: 1 addition & 4 deletions examples/ConsoleAppWithFailOver/Program.cs
Comment thread
linglingye001 marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,7 @@ private static void Configure()
IConfiguration configuration = builder.Build();

IConfigurationSection endpointsSection = configuration.GetSection("AppConfig:Endpoints");
IEnumerable<Uri> endpoints = endpointsSection.GetChildren()
.Select(endpoint => endpoint.Value)
.Where(value => !string.IsNullOrEmpty(value))
.Select(value => new Uri(value));
IEnumerable<Uri> endpoints = endpointsSection.GetChildren().Select(endpoint => new Uri(endpoint.Value));

Comment on lines 33 to 35
if (endpoints == null || !endpoints.Any())
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
//
using Azure.Data.AppConfiguration;
using Microsoft.Extensions.Azure;
using System;
using System.Collections.Generic;

namespace Microsoft.Extensions.Configuration.AzureAppConfiguration.Afd
{
internal class AfdClientManager : IAppConfigurationClientManager
{
private readonly AppConfigurationClient _clientWrapper;

public AfdClientManager(
IAzureClientFactory<ConfigurationClient> configurationClientFactory,
IAzureClientFactory<FeatureFlagClient> featureFlagClientFactory,
Uri endpoint)
{
if (configurationClientFactory == null)
{
throw new ArgumentNullException(nameof(configurationClientFactory));
}

if (featureFlagClientFactory == null)
{
throw new ArgumentNullException(nameof(featureFlagClientFactory));
}

if (endpoint == null)
{
throw new ArgumentNullException(nameof(endpoint));
}

_clientWrapper = new AppConfigurationClient(
endpoint,
configurationClientFactory.CreateClient(endpoint.AbsoluteUri),
featureFlagClientFactory.CreateClient(endpoint.AbsoluteUri));
}

public IEnumerable<IAppConfigurationClient> GetClients()
{
return new List<IAppConfigurationClient> { _clientWrapper };
}

public void RefreshClients()
{
return;
}

public bool UpdateSyncToken(Uri endpoint, string syncToken)
{
return false;
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
//
using Azure;
using Azure.Data.AppConfiguration;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.Extensions.Configuration.AzureAppConfiguration
{
/// <summary>
/// The default <see cref="IAppConfigurationClient"/> implementation. It holds a
/// <see cref="ConfigurationClient"/> for key-values (including feature flags) and a
/// <see cref="FeatureFlagClient"/> for enhanced feature flags served by the dedicated feature-flag endpoint,
/// both targeting the same <see cref="Endpoint"/>.
/// </summary>
internal class AppConfigurationClient : IAppConfigurationClient
{
private readonly ConfigurationClient _configurationClient;
private readonly FeatureFlagClient _featureFlagClient;

public AppConfigurationClient(Uri endpoint, ConfigurationClient configurationClient, FeatureFlagClient featureFlagClient)
{
Endpoint = endpoint;
_configurationClient = configurationClient ?? throw new ArgumentNullException(nameof(configurationClient));
_featureFlagClient = featureFlagClient ?? throw new ArgumentNullException(nameof(featureFlagClient));
}

public Uri Endpoint { get; }

public AsyncPageable<ConfigurationSetting> GetConfigurationSettingsAsync(SettingSelector selector, CancellationToken cancellationToken)
{
return _configurationClient.GetConfigurationSettingsAsync(selector, cancellationToken);
}

public AsyncPageable<ConfigurationSetting> CheckConfigurationSettingsAsync(SettingSelector selector, CancellationToken cancellationToken)
{
return _configurationClient.CheckConfigurationSettingsAsync(selector, cancellationToken);
}

public Task<Response<ConfigurationSetting>> GetConfigurationSettingAsync(string key, string label, CancellationToken cancellationToken)
{
return _configurationClient.GetConfigurationSettingAsync(key, label, cancellationToken);
}

public Task<Response<ConfigurationSetting>> GetConfigurationSettingAsync(ConfigurationSetting setting, bool onlyIfChanged, CancellationToken cancellationToken)
{
return _configurationClient.GetConfigurationSettingAsync(setting, onlyIfChanged, cancellationToken);
}

public Task<Response<ConfigurationSnapshot>> GetSnapshotAsync(string snapshotName, CancellationToken cancellationToken)
{
return _configurationClient.GetSnapshotAsync(snapshotName, cancellationToken: cancellationToken);
}

public AsyncPageable<ConfigurationSetting> GetConfigurationSettingsForSnapshotAsync(string snapshotName, CancellationToken cancellationToken)
{
return _configurationClient.GetConfigurationSettingsForSnapshotAsync(snapshotName, cancellationToken);
}

public AsyncPageable<FeatureFlag> GetFeatureFlagsAsync(FeatureFlagSelector selector, CancellationToken cancellationToken)
{
return _featureFlagClient.GetFeatureFlagsAsync(selector, cancellationToken);
}

public void UpdateSyncToken(string syncToken)
{
_configurationClient.UpdateSyncToken(syncToken);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,19 @@ namespace Microsoft.Extensions.Configuration.AzureAppConfiguration
/// This class is not thread-safe. Since config provider does not allow multiple network requests at the same time,
/// there won't be multiple threads calling this client at the same time.
/// </remarks>
internal class ConfigurationClientManager : IConfigurationClientManager, IDisposable
internal class AppConfigurationClientManager : IAppConfigurationClientManager, IDisposable
{
private readonly IAzureClientFactory<ConfigurationClient> _clientFactory;
private readonly IList<ConfigurationClientWrapper> _clients;
private readonly IAzureClientFactory<ConfigurationClient> _configurationClientFactory;
private readonly IAzureClientFactory<FeatureFlagClient> _featureFlagClientFactory;
private readonly IList<AppConfigurationClient> _clients;

private readonly Uri _endpoint;

private readonly bool _replicaDiscoveryEnabled;
private readonly SrvLookupClient _srvLookupClient;
private readonly string _validDomain;

private IList<ConfigurationClientWrapper> _dynamicClients;
private IList<AppConfigurationClient> _dynamicClients;
private DateTimeOffset _lastFallbackClientRefresh = default;
private DateTimeOffset _lastFallbackClientRefreshAttempt = default;
private Logger _logger = new Logger();
Expand All @@ -50,13 +51,15 @@ internal class ConfigurationClientManager : IConfigurationClientManager, IDispos
// Only used for unit testing
internal int RefreshClientsCalled { get; set; } = 0;

public ConfigurationClientManager(
IAzureClientFactory<ConfigurationClient> clientFactory,
public AppConfigurationClientManager(
IAzureClientFactory<ConfigurationClient> configurationClientFactory,
IAzureClientFactory<FeatureFlagClient> featureFlagClientFactory,
IEnumerable<Uri> endpoints,
bool replicaDiscoveryEnabled,
bool loadBalancingEnabled)
{
_clientFactory = clientFactory ?? throw new ArgumentNullException(nameof(clientFactory));
_configurationClientFactory = configurationClientFactory ?? throw new ArgumentNullException(nameof(configurationClientFactory));
_featureFlagClientFactory = featureFlagClientFactory ?? throw new ArgumentNullException(nameof(featureFlagClientFactory));

if (endpoints == null || !endpoints.Any())
{
Expand All @@ -77,20 +80,23 @@ public ConfigurationClientManager(
_srvLookupClient = new SrvLookupClient();

_clients = endpoints
.Select(endpoint => new ConfigurationClientWrapper(endpoint, clientFactory.CreateClient(endpoint.AbsoluteUri)))
.Select(endpoint => new AppConfigurationClient(
endpoint,
configurationClientFactory.CreateClient(endpoint.AbsoluteUri),
featureFlagClientFactory.CreateClient(endpoint.AbsoluteUri)))
.ToList();
}

/// <summary>
/// Internal constructor; Only used for unit testing.
/// </summary>
/// <param name="clients"></param>
internal ConfigurationClientManager(IList<ConfigurationClientWrapper> clients)
internal AppConfigurationClientManager(IList<AppConfigurationClient> clients)
{
_clients = clients;
}

public IEnumerable<ConfigurationClient> GetClients()
public IEnumerable<IAppConfigurationClient> GetClients()
{
DateTimeOffset now = DateTimeOffset.UtcNow;

Expand All @@ -105,11 +111,11 @@ public IEnumerable<ConfigurationClient> GetClients()
}

// Treat the passed in endpoints as the highest priority clients
IEnumerable<ConfigurationClient> clients = _clients.Select(c => c.Client);
IEnumerable<IAppConfigurationClient> clients = _clients;

if (_dynamicClients != null && _dynamicClients.Any())
{
clients = clients.Concat(_dynamicClients.Select(c => c.Client));
clients = clients.Concat(_dynamicClients);
}

return clients;
Expand Down Expand Up @@ -142,39 +148,22 @@ public bool UpdateSyncToken(Uri endpoint, string syncToken)
throw new ArgumentNullException(nameof(syncToken));
}

ConfigurationClientWrapper clientWrapper = _clients.SingleOrDefault(c => new EndpointComparer().Equals(c.Endpoint, endpoint));
AppConfigurationClient client = _clients.SingleOrDefault(c => new EndpointComparer().Equals(c.Endpoint, endpoint));

if (_dynamicClients != null && clientWrapper == null)
if (_dynamicClients != null && client == null)
{
clientWrapper = _dynamicClients.SingleOrDefault(c => new EndpointComparer().Equals(c.Endpoint, endpoint));
client = _dynamicClients.SingleOrDefault(c => new EndpointComparer().Equals(c.Endpoint, endpoint));
}

if (clientWrapper != null)
if (client != null)
{
clientWrapper.Client.UpdateSyncToken(syncToken);
client.UpdateSyncToken(syncToken);
return true;
}

return false;
}

public Uri GetEndpointForClient(ConfigurationClient client)
{
if (client == null)
{
throw new ArgumentNullException(nameof(client));
}

ConfigurationClientWrapper currentClient = _clients.FirstOrDefault(c => c.Client == client);

if (_dynamicClients != null && currentClient == null)
{
currentClient = _dynamicClients.FirstOrDefault(c => c.Client == client);
}

return currentClient?.Endpoint;
}

public void SetLogger(Logger logger)
{
if (logger == null)
Expand Down Expand Up @@ -231,7 +220,7 @@ private async Task RefreshFallbackClients(CancellationToken cancellationToken)
return;
}

var newDynamicClients = new List<ConfigurationClientWrapper>();
var newDynamicClients = new List<AppConfigurationClient>();

// Honor with the DNS based service discovery protocol, but shuffle the results first to ensure hosts can be picked randomly,
// Srv lookup does retrieve trailing dot in the host name, just trim it.
Expand All @@ -247,9 +236,11 @@ private async Task RefreshFallbackClients(CancellationToken cancellationToken)
{
var targetEndpoint = new Uri($"https://{host}");

ConfigurationClient configClient = _clientFactory.CreateClient(targetEndpoint.AbsoluteUri);
ConfigurationClient configClient = _configurationClientFactory.CreateClient(targetEndpoint.AbsoluteUri);

FeatureFlagClient featureFlagClient = _featureFlagClientFactory.CreateClient(targetEndpoint.AbsoluteUri);

newDynamicClients.Add(new ConfigurationClientWrapper(targetEndpoint, configClient));
newDynamicClients.Add(new AppConfigurationClient(targetEndpoint, configClient, featureFlagClient));
}
}

Expand Down
Loading
Loading