A wrapper for accessing environment variables from within a dotnet core application.
- Make it easy to add new environment variables to a project in a strongly typed way
- Use declarative meta data on settings using attributes
- Allow selectively using default values depending on the environment
- Abstract the interface for getting environment variables to allow easy unit testing with different values
- Abstract secrets access so that in code environment variables and secrets are all just "environment settings"
Create enum and mark values with SettingInfo
.
Example settings enum:
using MikeyT.EnvironmentSettingsNS.Attributes;
using MikeyT.EnvironmentSettingsNS.Enums;
public enum GlobalSettings
{
[SettingInfo(ShouldLogValue = true)]
ASPNETCORE_ENVIRONMENT,
[SettingInfo(DefaultValue = "localhost",
DefaultForEnvironment = DefaultSettingForEnvironment.LocalOnly,
ShouldLogValue = true)]
POSTGRES_HOST,
[SettingInfo(DefaultValue = "5432",
DefaultForEnvironment = DefaultSettingForEnvironment.LocalOnly,
ShouldLogValue = true)]
POSTGRES_PORT,
[SettingInfo(DefaultValue = "postgres",
DefaultForEnvironment = DefaultSettingForEnvironment.LocalOnly)]
POSTGRES_USER,
[SettingInfo(DefaultValue = "super_secret",
DefaultForEnvironment = DefaultSettingForEnvironment.LocalOnly)]
POSTGRES_PASSWORD,
[SettingInfo(DefaultValue = "my_db",
DefaultForEnvironment = DefaultSettingForEnvironment.AllEnvironments,
ShouldLogValue = true)]
DB_NAME,
[SettingInfo(DefaultValue = "SomeValue")]
SOME_KEY
}
Create a .env
file in your project so other developers can have different values. Add .env
to your .gitignore
so that your personal settings are not checked into source control.
Example .env
file:
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_USER=postgres
POSTGRES_PASSWORD=super_secret
In your Program.cs
load environment variables from .env
:
using MikeyT.EnvironmentSettingsNS.Logic;
public static void Main(string[] args)
{
DotEnv.Load();
// ...
}
In your Startup.cs
ConfigureServices
method, instantiate and populate settings, and then optionally setup dependency injection singleton:
using MikeyT.EnvironmentSettingsNS.Interface;
using MikeyT.EnvironmentSettingsNS.Logic;
private ILogger _logger;
private IEnvironmentSettings _envSettings;
public class Startup
{
_envSettings = new EnvironmentSettings(new EnvironmentVariableProvider());
_envSettings.AddSettings<GlobalSettings>();
// Log all environment variables that are white-listed for logging
_logger.Information("Loaded environment settings\n{EnvironmentSettings}", _envSettings.GetAllAsSafeLogString());
// Setup dependency injection
services.AddSingleton(_envSettings);
}
In a controller, use dependency injection to get an instance of IEnvironmentSettings
and use that to access settings:
[ApiController]
[Route("api/Weather/[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly ILogger<WeatherForecastController> _logger;
private readonly IWeatherGetter _weatherGetter;
private readonly IEnvironmentSettings _envSettings;
public WeatherForecastController(
ILogger<WeatherForecastController> logger,
IWeatherGetter weatherGetter,
IEnvironmentSettings envSettings)
{
_logger = logger;
_weatherGetter = weatherGetter;
_envSettings = envSettings;
}
[HttpGet("RandomForecasts")]
public IEnumerable<WeatherForecast> Get()
{
_logger.LogInformation(
"Your environment value for key SOME_KEY is {SomeKeyValue}",
envSettings.GetString(GlobalSettings.SOME_KEY));
return _weatherGetter.GetRandomWeatherForecasts();
}
}
Use different environment settings when unit testing by mocking IEnvironmentSettings
:
public enum YourSettings
{
[SettingInfo(DefaultValue = "SomeValue")]
SOME_KEY
}
public class YourClass
{
private readonly IEnvironmentSettings _envSettings;
public YourClass(IEnvironmentSettings envSettings)
{
_envSettings = envSettings;
}
// ...
}
public class YourClassTest
{
private YourClass _yourClass;
private Mock<IEnvironmentSettings> _envSettings = new();
public YourClassTest()
{
_yourClass = new YourClass(_envSettings.Object);
}
[Fact]
public void YourMethod_withSomeState_doesSomething()
{
// Arrange
_envSettings.Setup(ev => ev.GetString(YourSettings.SOME_KEY)).Returns("SomeTestValue");
// Act
// ...
// Assert
// ...
}
}