| | | 1 | | using ArturRios.Configuration.Enums; |
| | | 2 | | using DotNetEnv; |
| | | 3 | | using Microsoft.Extensions.Configuration; |
| | | 4 | | using Microsoft.Extensions.Logging; |
| | | 5 | | |
| | | 6 | | namespace ArturRios.Configuration.Loaders; |
| | | 7 | | |
| | | 8 | | /// <summary> |
| | | 9 | | /// Provides helper methods to load environment variables from <c>.env</c> files and |
| | | 10 | | /// application settings from <c>appsettings.<Environment>.json</c> files. |
| | | 11 | | /// </summary> |
| | | 12 | | /// <remarks> |
| | | 13 | | /// By default, it looks for files under the <c>Environments</c> and <c>Settings</c> folders within the application base |
| | | 14 | | /// If a specific environment file is not found, it falls back to the <see cref="EnvironmentType.Local"/> environment. |
| | | 15 | | /// </remarks> |
| | | 16 | | public class ConfigurationLoader |
| | | 17 | | { |
| | | 18 | | /// <summary> |
| | | 19 | | /// Default environment name used when a specific environment file cannot be found. |
| | | 20 | | /// </summary> |
| | | 21 | | private const string DefaultEnvironmentName = nameof(EnvironmentType.Local); |
| | | 22 | | /// <summary> |
| | | 23 | | /// Default folder name that contains <c>.env</c> files. |
| | | 24 | | /// </summary> |
| | | 25 | | private const string DefaultEnvFileFolder = "Environments"; |
| | | 26 | | /// <summary> |
| | | 27 | | /// Default folder name that contains <c>appsettings</c> files. |
| | | 28 | | /// </summary> |
| | | 29 | | private const string DefaultAppSettingsFolder = "Settings"; |
| | | 30 | | private readonly string _basePath; |
| | | 31 | | private readonly IConfigurationBuilder? _configurationBuilder; |
| | | 32 | | private readonly string _environmentName; |
| | | 33 | | private readonly ILogger<ConfigurationLoader> _logger; |
| | | 34 | | |
| | | 35 | | /// <summary> |
| | | 36 | | /// Initializes a new instance of <see cref="ConfigurationLoader"/> using an existing <see cref="IConfigurationBuild |
| | | 37 | | /// </summary> |
| | | 38 | | /// <param name="configurationBuilder">The configuration builder where JSON files will be added.</param> |
| | | 39 | | /// <param name="environmentName">The environment name (e.g., <c>Local</c>, <c>Development</c>, <c>Staging</c>, <c>P |
| | | 40 | | /// <param name="basePath">Optional base path to search for files. If not provided, the current domain base director |
| | | 41 | | /// <param name="logger">Optional logger instance. If not provided, a console logger is created.</param> |
| | 3 | 42 | | public ConfigurationLoader(IConfigurationBuilder configurationBuilder, string environmentName, |
| | 3 | 43 | | string? basePath = null, ILogger<ConfigurationLoader>? logger = null) |
| | 3 | 44 | | { |
| | 3 | 45 | | _configurationBuilder = configurationBuilder; |
| | 3 | 46 | | _environmentName = environmentName; |
| | 3 | 47 | | _basePath = string.IsNullOrEmpty(basePath) ? AppDomain.CurrentDomain.BaseDirectory : basePath; |
| | 3 | 48 | | _logger = logger ?? LoggerFactory.Create(builder => builder.AddConsole()).CreateLogger<ConfigurationLoader>(); |
| | 3 | 49 | | } |
| | | 50 | | |
| | | 51 | | /// <summary> |
| | | 52 | | /// Initializes a new instance of <see cref="ConfigurationLoader"/> without a configuration builder. |
| | | 53 | | /// </summary> |
| | | 54 | | /// <param name="environmentName">The environment name (e.g., <c>Local</c>, <c>Development</c>, <c>Staging</c>, <c>P |
| | | 55 | | /// <param name="basePath">Optional base path to search for files. If not provided, the current domain base director |
| | | 56 | | /// <param name="logger">Optional logger instance. If not provided, a console logger is created.</param> |
| | | 57 | | /// <remarks> |
| | | 58 | | /// Use <see cref="LoadEnvironment"/> with this constructor. <see cref="LoadAppSettings"/> requires an <see cref="IC |
| | | 59 | | /// </remarks> |
| | 4 | 60 | | public ConfigurationLoader(string environmentName, string? basePath = null, |
| | 4 | 61 | | ILogger<ConfigurationLoader>? logger = null) |
| | 4 | 62 | | { |
| | 4 | 63 | | _environmentName = environmentName; |
| | 4 | 64 | | _basePath = string.IsNullOrEmpty(basePath) ? AppDomain.CurrentDomain.BaseDirectory : basePath; |
| | 4 | 65 | | _logger = logger ?? LoggerFactory.Create(builder => builder.AddConsole()).CreateLogger<ConfigurationLoader>(); |
| | 4 | 66 | | } |
| | | 67 | | |
| | | 68 | | /// <summary> |
| | | 69 | | /// Loads environment variables from a specific <c>.env</c> file based on the configured environment. |
| | | 70 | | /// </summary> |
| | | 71 | | /// <remarks> |
| | | 72 | | /// It looks for <c>Environments/.env.<environment></c> and falls back to <c>Environments/.env.local</c> if no |
| | | 73 | | /// </remarks> |
| | | 74 | | public void LoadEnvironment() |
| | 3 | 75 | | { |
| | 3 | 76 | | var envFolder = Path.Combine(_basePath, DefaultEnvFileFolder); |
| | 3 | 77 | | var envFile = Path.Combine(envFolder, $".env.{_environmentName.ToLower()}"); |
| | 3 | 78 | | var defaultEnvFile = Path.Combine(envFolder, $".env.{DefaultEnvironmentName.ToLower()}"); |
| | | 79 | | |
| | 3 | 80 | | if (File.Exists(envFile)) |
| | 1 | 81 | | { |
| | 1 | 82 | | _logger.LogInformation("Loading variables for {EnvironmentName} environment...", _environmentName); |
| | | 83 | | |
| | 1 | 84 | | Env.Load(envFile); |
| | 1 | 85 | | } |
| | 2 | 86 | | else if (File.Exists(defaultEnvFile)) |
| | 1 | 87 | | { |
| | 1 | 88 | | _logger.LogInformation( |
| | 1 | 89 | | "Could not find variables for {EnvironmentName} environment. Loading default environment {DefaultEnviron |
| | 1 | 90 | | _environmentName, DefaultEnvironmentName); |
| | | 91 | | |
| | 1 | 92 | | Env.Load(defaultEnvFile); |
| | 1 | 93 | | } |
| | | 94 | | else |
| | 1 | 95 | | { |
| | 1 | 96 | | _logger.LogInformation("Could not find any environment variables"); |
| | 1 | 97 | | } |
| | 3 | 98 | | } |
| | | 99 | | |
| | | 100 | | /// <summary> |
| | | 101 | | /// Loads JSON application settings for the configured environment into the provided <see cref="IConfigurationBuilde |
| | | 102 | | /// </summary> |
| | | 103 | | /// <exception cref="InvalidOperationException">Thrown when no <see cref="IConfigurationBuilder"/> was provided in t |
| | | 104 | | /// <remarks> |
| | | 105 | | /// It looks for <c>Settings/appsettings.<environment>.json</c> and falls back to <c>Settings/appsettings.loca |
| | | 106 | | /// </remarks> |
| | | 107 | | public void LoadAppSettings() |
| | 4 | 108 | | { |
| | 4 | 109 | | var settingsFolder = Path.Combine(_basePath, DefaultAppSettingsFolder); |
| | 4 | 110 | | var envSettingsFile = Path.Combine(settingsFolder, $"appsettings.{_environmentName}.json"); |
| | 4 | 111 | | var defaultSettingsFile = Path.Combine(settingsFolder, $"appsettings.{DefaultEnvironmentName}.json"); |
| | | 112 | | |
| | 4 | 113 | | if (_configurationBuilder is null) |
| | 1 | 114 | | { |
| | 1 | 115 | | throw new InvalidOperationException( |
| | 1 | 116 | | "Cannot load appsettings.json if configuration builder is not provided on constructor"); |
| | | 117 | | } |
| | | 118 | | |
| | 3 | 119 | | if (File.Exists(envSettingsFile)) |
| | 1 | 120 | | { |
| | 1 | 121 | | _logger.LogInformation("Loading app settings for {EnvironmentName} environment...", _environmentName); |
| | | 122 | | |
| | 1 | 123 | | _configurationBuilder.AddJsonFile(envSettingsFile, false, true); |
| | 1 | 124 | | } |
| | 2 | 125 | | else if (File.Exists(defaultSettingsFile)) |
| | 1 | 126 | | { |
| | 1 | 127 | | _logger.LogInformation( |
| | 1 | 128 | | "Could not find app settings for {EnvironmentName} environment. Loading default environment {DefaultEnvi |
| | 1 | 129 | | _environmentName, DefaultEnvironmentName); |
| | | 130 | | |
| | 1 | 131 | | _configurationBuilder.AddJsonFile(defaultSettingsFile, false, true); |
| | 1 | 132 | | } |
| | | 133 | | else |
| | 1 | 134 | | { |
| | 1 | 135 | | _logger.LogInformation("Could not find any app settings"); |
| | 1 | 136 | | } |
| | 3 | 137 | | } |
| | | 138 | | } |