From 6ad30f51cb9d53a90520805e5b688e4afe1b52e0 Mon Sep 17 00:00:00 2001 From: Robert Friberg Date: Sun, 19 Nov 2023 18:12:19 +0100 Subject: [PATCH] add SettingsBuilder.UseEnvironmentVariable() --- Fig.Core/SettingsBuilder.cs | 20 +++++++++++++++- Fig.Tests/ArrayBindingTests.cs | 30 +++++++++++++++++++++++ Fig.Tests/appsettings.TEST.json | 11 +-------- Fig.Tests/appsettings.json | 11 +-------- README.md | 42 +++++++++++++++++++++++++-------- 5 files changed, 83 insertions(+), 31 deletions(-) create mode 100644 Fig.Tests/ArrayBindingTests.cs diff --git a/Fig.Core/SettingsBuilder.cs b/Fig.Core/SettingsBuilder.cs index 85f50f7..9409da7 100644 --- a/Fig.Core/SettingsBuilder.cs +++ b/Fig.Core/SettingsBuilder.cs @@ -42,7 +42,7 @@ public SettingsBuilder UseDotEnv(string fileName = ".env", string directory = ". /// The path separator (default is _) will be translated to a dot /// /// For example FIG_, default is no prefix. - /// When true, the prefix will not be included in the key + /// When true, the prefix will not be included in the key. default is true /// public SettingsBuilder UseEnvironmentVariables(string prefix = "", bool dropPrefix = true) { @@ -50,6 +50,24 @@ public SettingsBuilder UseEnvironmentVariables(string prefix = "", bool dropPref return this; } + /// + /// Read a single environment variable + /// + /// the name of the environment variable + /// + /// + /// Thrown if the variable is required but not defined + public SettingsBuilder UseEnvironmentVariable(string name, bool required = false) + { + var val = Environment.GetEnvironmentVariable(name); + if (val is null && required) throw new ConfigurationException("Required ENV var not found: " + name); + if (val != null) Add(new SettingsDictionary() + { + [name] = val + }); + return this; + } + private void Add(SettingsDictionary settingsDictionary) { _layeredDictionary.Add(settingsDictionary); diff --git a/Fig.Tests/ArrayBindingTests.cs b/Fig.Tests/ArrayBindingTests.cs new file mode 100644 index 0000000..fc808ae --- /dev/null +++ b/Fig.Tests/ArrayBindingTests.cs @@ -0,0 +1,30 @@ +using NUnit.Framework; + +namespace Fig.Test; + +public class ArrayBindingTests +{ + [Test] + public void CanBindToArray() + { + var settings = new SettingsBuilder() + .UseAppSettingsJson("appsettings.json", required: true) + .Build(); + + var servers = settings.Get("Servers"); + Assert.AreEqual(2,servers.Length); + Assert.AreEqual("10.0.0.1", servers[0]); + Assert.AreEqual("10.0.0.2", servers[1]); + + var mySettings = settings.Bind(path:""); + Assert.AreEqual(2, mySettings.Servers.Length); + Assert.AreEqual("10.0.0.1", mySettings.Servers[0]); + Assert.AreEqual("10.0.0.2", mySettings.Servers[1]); + + } + + private class MySettings + { + public string[] Servers { get; set; } + } +} \ No newline at end of file diff --git a/Fig.Tests/appsettings.TEST.json b/Fig.Tests/appsettings.TEST.json index 4a47eb6..62024bf 100644 --- a/Fig.Tests/appsettings.TEST.json +++ b/Fig.Tests/appsettings.TEST.json @@ -13,14 +13,5 @@ "Simpsons" : [ { "Name" : "Bart", "Age" : 12}, { "Name" : "Homer", "Age" : 35} - ], - - "EnvQualified:PROD" : { - "a" : 1, - "b" : 1 - }, - "EnvQualified:TEST" : { - "a" : 2, - "b" : 2 - } + ] } diff --git a/Fig.Tests/appsettings.json b/Fig.Tests/appsettings.json index 2881261..352c335 100644 --- a/Fig.Tests/appsettings.json +++ b/Fig.Tests/appsettings.json @@ -14,14 +14,5 @@ "Simpsons" : [ { "Name" : "Bart", "Age" : 12}, { "Name" : "Homer", "Age" : 35} - ], - - "EnvQualified:PROD" : { - "a" : 1, - "b" : 1 - }, - "EnvQualified:TEST" : { - "a" : 2, - "b" : 2 - } + ] } diff --git a/README.md b/README.md index 580f64a..e1f0abe 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ A .NET Standard 2.0 library to help you read application configuration settings This README is the documentation. +Breaking changes with version 2.0, please read the [Release notes]() carefully before upgrading from an older version. + ## Documentation Do you have code like the following sprinkled across your code base? @@ -99,6 +101,25 @@ DbSettings.ConnectionString NetworkSettings.TcpPort NetworkSettings.Retries ``` +## Binding to arrays +Append indicies to your configuration keys to define an array: + +``` +Servers.0 = 10.0.0.1 +Servers.1 = 10.0.0.2 +``` + +and then bind to a property of type array: + +```csharp + class MySettings + { + public string[] Servers { get; set;} + } +``` +Arrays in json files will work this way. See the section below on appsettings.json. + +## Variable substitution ## Binding Validation Properties are either required or optional. To make a property optional, assign it a non-null value before binding. @@ -122,6 +143,7 @@ So given the following class: the `RefillInterval` and `EnableEspressoMachine` parameters are required while the `Greeting` property is optional. + ## Retrieving values by key For simple applications with just a few parameters defining a custom class could be considered over-engineering. In this case you can retrieve values directly by key, either as strings or converted to a desired type. @@ -300,7 +322,7 @@ overloads to setup a connection to your database. ``` The SQL query used is `SELECT key, value FROM FigSettings`. You can pass your own query: -``` +```csharp var settings = new SettingsBuilder() .UseAppSettingsJson("appsettings.json") .UseSql("ConnectionStrings.SQLiteConnection", "SELECT a,b FROM MySettings") @@ -314,16 +336,16 @@ lower layers. ```c# var settings = new SettingsBuilder() + .UseEnvironmentVariable("ENV") .UseAppSettingsJson("appSettings.json") - .UseAppSettingsJson("appSettings.${ENV}.json", optional:true) + .UseAppSettingsJson("appSettings.${ENV}.json", required:false) .UseDotEnv() - .UseEnvironmentVariables(prefix: "FIG_", dropPrefix:false) + .UseEnvironmentVariables() .UseCommandLine(args) .Build(); ``` -Notice the environment specific json file. The variable `${ENV}` -will be looked up based on what has been added so far: -environment variables and command line. +Notice the variable substitution in the second json file. The variable `${ENV}` +will be looked up in the settings dictionary built so far. ## Install from nuget ```bash @@ -347,11 +369,11 @@ with keys and values of each layer: ``` -------------------- Layer 0 ---------------------- -| Network.ip:TEST | 127.0.0.1 | -| Network.port:TEST | 13001 | +| Network.ip | 127.0.0.1 | +| Network.port | 13001 | -------------------- Layer 1 ---------------------- -| Network.ip:PROD | 10.0.0.1 | -| Network.port:PROD | 3001 | +| Network.ip | 10.0.0.1 | +| Network.port | 3001 | --------------------------------------------------- ```