Skip to content

Commit

Permalink
Merge pull request #45 from sia-digital/feature/orderd_configurations
Browse files Browse the repository at this point in the history
fix ordering of appsettings
  • Loading branch information
fb-smit authored Feb 21, 2024
2 parents cf3344f + 7fe32c6 commit 5077c60
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 27 deletions.
30 changes: 23 additions & 7 deletions PiBox.Hosting/WebHost/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,29 @@ PluginWebHostBuilder.RunDefault(PiBox.Generated.PiBoxPluginTypes.All);

PiBox will try to load config files and values in the following order

1. `appsettings*.json`
2. `appsettings*.yaml`
3. `appsettings*.yml`
4. `appsettings.json`
5. `appsettings.yaml`
6. `appsettings.yml`
7. ENV variables
1. `appsettings.json`
2. `appsettings.yaml`
3. `appsettings.yml`
4. `appsettings.*.json`
5. `appsettings.*.yaml`
6. `appsettings.*.yml`
7. `appsettings.secrets.yml`
8. `appsettings.*.secrets.yml`
9`ENV variables`

**NOTE:**
All settings (does not matter which file extension) will be ordered by node length. And the secret files will be loaded as last (except the environment variables).

Example:

1. appsettings.yaml
2. appsettings.api.yaml
3. appsettings.api.host.yaml
4. appsettings.secrets.yaml
5. apssettings.api.secrets.yaml
6. appsettings.api.host.secrets.yaml
7. ENV Variables


File names must always start with `appsettings` or they will be ignored!

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using PiBox.Hosting.Abstractions.Configuration;
using PiBox.Hosting.WebHost.Extensions;
using PiBox.Hosting.WebHost.Logging;

namespace PiBox.Hosting.WebHost.Configurators
Expand Down Expand Up @@ -30,27 +31,28 @@ internal static void ConfigureAppConfiguration(ConfigurationManager configuratio

configurationManager.Sources.Clear();

foreach (var jsonConfig in FindAppSettingFiles(".json"))
configurationManager.AddJsonFile(jsonConfig, optional: true, reloadOnChange: true);
var settings = FindAppSettingFiles("json", "yaml", "yml").ToList();
foreach (var file in settings.Where(x => !IsSecretsFile(x)))
configurationManager.AddFile(file);

foreach (var yamlFile in FindAppSettingFiles(".yaml", ".yml"))
configurationManager.AddYamlFile(yamlFile, optional: true, reloadOnChange: true);
foreach (var file in settings.Where(IsSecretsFile))
configurationManager.AddFile(file);

configurationManager.AddJsonFile("appsettings.json", true, true)
.AddYamlFile("appsettings.yaml", true, true)
.AddYamlFile("appsettings.yml", true, true)
.AddEnvVariables();
configurationManager.AddEnvVariables();
#pragma warning restore ASP0013
}

private static bool IsSecretsFile(string filename) => filename.EndsWith(".secrets.yaml") ||
filename.EndsWith(".secrets.yml") ||
filename.EndsWith(".secrets.json");

private static IEnumerable<string> FindAppSettingFiles(params string[] extensions)
{
var files = Directory.GetFiles(Environment.CurrentDirectory)
.Select(x => x.Split(Path.DirectorySeparatorChar).Last())
.Where(x => !string.IsNullOrEmpty(x) && x.StartsWith("appsettings", StringComparison.InvariantCulture))
.Where(x => extensions.Any(e => x.EndsWith(e, StringComparison.InvariantCulture)))
.Where(x => !extensions.Any(
e => string.Equals(x, "appsettings" + e, StringComparison.OrdinalIgnoreCase)))
.Where(x => !string.IsNullOrEmpty(x) && x.StartsWith("appsettings.", StringComparison.InvariantCulture))
.Where(x => extensions.Any(e => x.EndsWith(e, StringComparison.InvariantCultureIgnoreCase)))
.OrderBy(x => x.Split('.').Length)
.ToList();

return files;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Microsoft.Extensions.Configuration;

namespace PiBox.Hosting.WebHost.Extensions
{
internal static class ConfigurationManagerExtensions
{
public static void AddFile(this ConfigurationManager configurationManager, string file, bool optional = true, bool reloadOnChange = true)
{
if (file.EndsWith(".json"))
configurationManager.AddJsonFile(file, optional, reloadOnChange);
else if (file.EndsWith(".yaml") || file.EndsWith(".yml"))
configurationManager.AddYamlFile(file, optional, reloadOnChange);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
<None Update="appsettings.yml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="appsettings.test.yml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="appsettings.test.secrets.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,20 @@ public async Task ShouldWork()
webApplication.Logger.GetType().Name.Should().Be("SerilogLogger");
var configurationProviders = webApplication.Configuration.As<IConfigurationRoot>().Providers.ToList();

configurationProviders[0].Should().BeOfType<JsonConfigurationProvider>();
configurationProviders[0].As<JsonConfigurationProvider>().Source.Path.Should().Be("appsettings.json");
configurationProviders[0].Should().BeOfType<YamlConfigurationProvider>();
configurationProviders[0].As<YamlConfigurationProvider>().Source.Path.Should().Be("appsettings.yml");

configurationProviders[1].Should().BeOfType<YamlConfigurationProvider>();
configurationProviders[1].As<YamlConfigurationProvider>().Source.Path.Should().Be("appsettings.yaml");
configurationProviders[1].As<YamlConfigurationProvider>().Source.Path.Should().Be("appsettings.test.yml");

configurationProviders[2].Should().BeOfType<YamlConfigurationProvider>();
configurationProviders[2].As<YamlConfigurationProvider>().Source.Path.Should().Be("appsettings.yml");
configurationProviders[2].TryGet("serilog:minimumLevel", out var loglevel);
loglevel.Should().Be("Debug");
configurationProviders[2].Should().BeOfType<JsonConfigurationProvider>();
configurationProviders[2].As<JsonConfigurationProvider>().Source.Path.Should().Be("appsettings.test.secrets.json");

configurationProviders[3].Should().BeOfType<EnvConfigurationProvider>();

var logLevel = webApplication.Configuration.GetValue<string>("serilog:minimumLevel");
logLevel.Should().Be("Information"); // overriden from appsettings.test.secrets.json

var ipRateLimitOptions = webApplication.Configuration.BindToSection<IpRateLimitOptions>("IpRateLimiting");
ipRateLimitOptions.EnableEndpointRateLimiting.Should().BeFalse();
ipRateLimitOptions.StackBlockedRequests.Should().BeFalse();
Expand Down Expand Up @@ -124,7 +125,7 @@ public async Task ShouldWork()
apiBehaviourOptions.InvalidModelStateResponseFactory.Should().Be(modelStateResponseFactory);

var sampleConfig = webApplication.Configuration.BindToSection<TypeImplementationResolverTests.UnitTestPluginConfig>("sampleConfig");
sampleConfig.Name.Should().Be("example");
sampleConfig.Name.Should().Be("example1"); // overridden from appsettings.test.yml
var unitTestPluginConfig = host.Services.GetRequiredService<TypeImplementationResolverTests.UnitTestPluginConfig>();
unitTestPluginConfig.Should().NotBeNull();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"serilog": {
"minimumLevel": "Information"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
IpRateLimiting:
EnableEndpointRateLimiting: false
StackBlockedRequests: false
RealIpHeader: X-Real-IP
ClientIdHeader: X-ClientId
HttpStatusCode: 429
IpWhitelist:
- 127.0.0.1
- "::1/10"
- 192.168.0.0/24
EndpointWhitelist:
- get:/api/license
- "*:/api/status"
ClientWhitelist:
- dev-id-1
- dev-id-2
GeneralRules:
- Endpoint: "*"
Period: 1s
Limit: 2
- Endpoint: "*"
Period: 15m
Limit: 100
- Endpoint: "*"
Period: 12h
Limit: 1000
- Endpoint: "*"
Period: 7d
Limit: 10000

IpRateLimitPolicies:
IpRules:
- Ip: 84.247.85.224
Rules:
- Endpoint: "*"
Period: 1s
Limit: 10
- Ip: 192.168.3.22/25
Rules:
- Endpoint: "*"
Period: 12h
Limit: 500

CorsPolicy:
Origins:
- "http://localhost:4200"
- "http://localhost:4201"
Methods:
- "POST"
SupportsCredentials: "true"

sampleConfig:
name: example1

0 comments on commit 5077c60

Please sign in to comment.