Adds option pattern for smart config

This commit is contained in:
Janus C. H. Knudsen 2025-02-11 23:10:43 +01:00
parent 6839cd82e2
commit f4f2fc47b1
6 changed files with 130 additions and 87 deletions

View file

@ -3,6 +3,7 @@ using Core.Configurations.SmartConfigProvider;
namespace Core.Configurations.SmartConfiguration; namespace Core.Configurations.SmartConfiguration;
public interface IConfigurationRepository public interface IConfigurationRepository
{ {
string ConnectionString { get; set; }
IEnumerable<AppConfiguration> GetActiveConfigurations(); IEnumerable<AppConfiguration> GetActiveConfigurations();
} }

View file

@ -2,21 +2,25 @@ using System.Data;
using Core.Configurations.SmartConfiguration; using Core.Configurations.SmartConfiguration;
using Insight.Database; using Insight.Database;
namespace Core.Configurations.SmartConfigProvider; namespace Core.Configurations.SmartConfigProvider.Repositories;
public class ConfigurationRepository : IConfigurationRepository public class PostgresConfigurationRepository : IConfigurationRepository
{ {
private readonly IDbConnection _connection; private IDbConnection _connection;
public string ConnectionString { get; set; }
public ConfigurationRepository(IDbConnection connection)
{ public PostgresConfigurationRepository(string connectionString)
_connection = connection;
}
public ConfigurationRepository(string connectionString)
{ {
_connection = new Npgsql.NpgsqlConnection(connectionString); _connection = new Npgsql.NpgsqlConnection(connectionString);
}
public PostgresConfigurationRepository()
{
} }
public IEnumerable<AppConfiguration> GetActiveConfigurations() public IEnumerable<AppConfiguration> GetActiveConfigurations()
{ {
_connection ??= new Npgsql.NpgsqlConnection(ConnectionString);
const string sql = @" const string sql = @"
SELECT id, ""key"", value, label, content_type, SELECT id, ""key"", value, label, content_type,
valid_from, expires_at, created_at, modified_at, etag valid_from, expires_at, created_at, modified_at, etag

View file

@ -1,10 +1,4 @@
using Core.Configurations.JsonConfigProvider; namespace Core.Configurations.SmartConfig
using Core.Configurations.SmartConfigProvider;
using Core.Exceptions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Core.Configurations.SmartConfig
{ {
public static class SmartConfigExtension public static class SmartConfigExtension
{ {
@ -24,78 +18,7 @@ namespace Core.Configurations.SmartConfig
var options = new SmartConfigOptions(); var options = new SmartConfigOptions();
setupAction(options); setupAction(options);
return builder.AddProvider(new SmartConfigProvider(options.GetRepository())); return builder.AddProvider(new SmartConfigProvider(builder, options));
}
}
public class SmartConfigOptions
{
private SmartConfiguration.IConfigurationRepository _repository;
public SmartConfigOptions UseRepository(SmartConfiguration.IConfigurationRepository repository)
{
_repository = repository;
return this;
}
internal SmartConfiguration.IConfigurationRepository GetRepository() => _repository;
}
public class SmartConfigProvider : IConfigurationProvider
{
string _configKey;
string _connectionString;
string _path;
IConfigurationBuilder _builder;
Newtonsoft.Json.Linq.JObject _configuration;
public SmartConfigProvider() { }
public SmartConfigProvider(SmartConfiguration.IConfigurationRepository configurationProvider)
{ }
public SmartConfigProvider(IConfigurationBuilder builder, string configKey, string configurationFilePath)
{
_builder = builder;
_configKey = configKey;
_path = configurationFilePath;
SetConnectionString();
}
void SetConnectionString()
{
var carrier = _builder.ConfigurationProviders.OfType<IHasConfigurationFilePath>().SingleOrDefault();
if (carrier?.ConfigurationFilePath is null && _path is null)
throw new ConfigurationException($"Expected a previous added ConfigurationProvider with IHasConfigurationFilePath or a configurationFilePath where to find the appsettingsfile");
_path ??= carrier.ConfigurationFilePath;
if (!File.Exists(_path))
throw new ConfigurationException($"File not found, configurationFilePath: {_path}");
using (StreamReader file = File.OpenText(_path))
using (JsonTextReader reader = new JsonTextReader(file))
{
var jsonConfiguration = (Newtonsoft.Json.Linq.JObject)Newtonsoft.Json.Linq.JToken.ReadFrom(reader);
_connectionString = jsonConfiguration.SelectToken($"ConnectionStrings.{_configKey}")?.ToString();
}
}
public void Build()
{
var repository = new ConfigurationRepository(_connectionString);
var configs = repository.GetActiveConfigurations();
var pairs = configs.Select(x => new KeyValuePair<string, JToken>(x.Key, JToken.Parse(x.Value.ToString())));
_configuration = Common.KeyValueToJson.Convert(pairs);
}
public Newtonsoft.Json.Linq.JObject Configuration()
{
return _configuration;
} }
} }
} }

View file

@ -0,0 +1,28 @@
namespace Core.Configurations.SmartConfig
{
public class SmartConfigOptions
{
private SmartConfiguration.IConfigurationRepository _repository;
internal string _configKey;
public SmartConfigOptions UsePostgres(string configKey)
{
_configKey = configKey;
_repository = new Configurations.SmartConfigProvider.Repositories.PostgresConfigurationRepository();
return this;
}
public SmartConfigOptions UseSqlServer()
{
throw new NotImplementedException();
}
public SmartConfigOptions UseRepository(SmartConfiguration.IConfigurationRepository repository)
{
_repository = repository;
return this;
}
internal SmartConfiguration.IConfigurationRepository GetRepository() => _repository;
}
}

View file

@ -0,0 +1,75 @@
using Core.Configurations.JsonConfigProvider;
using Core.Exceptions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Core.Configurations.SmartConfig
{
public class SmartConfigProvider : IConfigurationProvider
{
string _configKey;
string _connectionString;
string _path;
IConfigurationBuilder _builder;
Newtonsoft.Json.Linq.JObject _configuration;
SmartConfigOptions _smartConfigOptions;
public SmartConfigProvider() { }
public SmartConfigProvider(IConfigurationBuilder builder, SmartConfigOptions smartConfigOptions)
{
_builder = builder;
_smartConfigOptions = smartConfigOptions;
_configKey = smartConfigOptions._configKey;
SetConnectionString();
}
public SmartConfigProvider(IConfigurationBuilder builder, string configKey, string configurationFilePath)
{
_builder = builder;
_configKey = configKey;
_path = configurationFilePath;
SetConnectionString();
}
void SetConnectionString()
{
var carrier = _builder.ConfigurationProviders.OfType<IHasConfigurationFilePath>().SingleOrDefault();
if (carrier?.ConfigurationFilePath is null && _path is null)
throw new ConfigurationException($"Expected a previous added ConfigurationProvider with IHasConfigurationFilePath or a configurationFilePath where to find the appsettingsfile");
_path ??= carrier.ConfigurationFilePath;
if (!File.Exists(_path))
throw new ConfigurationException($"File not found, configurationFilePath: {_path}");
using (StreamReader file = File.OpenText(_path))
using (JsonTextReader reader = new JsonTextReader(file))
{
var jsonConfiguration = (Newtonsoft.Json.Linq.JObject)Newtonsoft.Json.Linq.JToken.ReadFrom(reader);
_connectionString = jsonConfiguration.SelectToken($"ConnectionStrings.{_configKey}")?.ToString();
}
}
public void Build()
{
var repository = _smartConfigOptions.GetRepository();
repository.ConnectionString = _connectionString;
var configs = repository.GetActiveConfigurations();
var pairs = configs.Select(x => new KeyValuePair<string, JToken>(x.Key, JToken.Parse(x.Value.ToString())));
_configuration = Common.KeyValueToJson.Convert(pairs);
}
public Newtonsoft.Json.Linq.JObject Configuration()
{
return _configuration;
}
}
}

View file

@ -7,6 +7,7 @@ using Autofac;
using System.Data; using System.Data;
using Insight.Database; using Insight.Database;
using Npgsql; using Npgsql;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Tests.ConfigurationTests namespace Tests.ConfigurationTests
{ {
@ -14,6 +15,17 @@ namespace Tests.ConfigurationTests
public class SmartConfigProviderTests : TestFixture public class SmartConfigProviderTests : TestFixture
{ {
[TestMethod]
public void TrySmartConfigWithOptionsForPostgres()
{
var config = new ConfigurationBuilder()
.AddJsonFile("appconfiguration.dev.json")
.AddSmartConfig(options => options.UsePostgres("DefaultConnection"))
.Build();
var actualFeature = config.Get<bool>("Database:UseSSL");
}
[TestMethod] [TestMethod]
public void Get_ShouldReturnCorrectValueAsBool() public void Get_ShouldReturnCorrectValueAsBool()
{ {