Skip to content

Smusdi WEB API configuration

Note

3 environment variables are used to setup the application configuration:

  • ASPNETCORE_ENVIRONMENT
  • SMUSDI_APPSETTINGS_FOLDER
  • SMUSDI_SERVICE_NAME

Implementation overview

The Smusdi service adds some configuration providers to the default ones and update the default json files configuration providers.

var webApplicationOptions = new WebApplicationOptions
        {
            Args = args,
        };

var builder = WebApplication.CreateBuilder(webApplicationOptions)
    .InitConfiguration();

And the InitConfiguration extension method:

namespace Smusdi.Core.Configuration;

public static class ConfigurationBuilding
{
    public static WebApplicationBuilder InitConfiguration(this WebApplicationBuilder webApplicationBuilder, string[]? args)
    {
        webApplicationBuilder.Configuration.InitConfiguration(webApplicationBuilder.Environment.EnvironmentName, args);
        return webApplicationBuilder;
    }

    public static HostApplicationBuilder InitConfiguration(this HostApplicationBuilder hostApplicationBuilder, string[]? args)
    {
        hostApplicationBuilder.Configuration.InitConfiguration(hostApplicationBuilder.Environment.EnvironmentName, args);
        return hostApplicationBuilder;
    }

    public static void InitConfiguration(this ConfigurationManager configuration, string environmentName, string[]? args)
    {
        // Cleanup already registered file config sources as the reset of the base path does not affect the sources, the associated provider is not reset!
        foreach (var fileSource in configuration.Sources.OfType<FileConfigurationSource>())
        {
            fileSource.FileProvider = null;
        }

        configuration.SetBasePath(GetConfigFilesFolder());

        var serviceName = Environment.GetEnvironmentVariable(SmusdiConstants.SmusdiServiceNameEnvVar);
        if (!string.IsNullOrWhiteSpace(serviceName))
        {
            configuration
                .AddJsonFile($"appsettings.{serviceName}.json", true, true)
                .AddJsonFile($"appsettings.{serviceName}.{environmentName}.json", true, true);
        }

        if (args is { Length: > 0 })
        {
            // already done during default construction. But, the previous files may have overwritten these values.
            configuration.AddCommandLine(args);
        }

        configuration
            .EnableEnvironmentVariablesExpansion();
    }

    public static string GetConfigFilesFolder()
    {
        var basePath = Environment.ExpandEnvironmentVariables(Environment.GetEnvironmentVariable(SmusdiConstants.SmusdiAppsettingsFolderEnvVar) ?? string.Empty);
        return Directory.Exists(basePath) ? Path.GetFullPath(basePath) : Directory.GetCurrentDirectory();
    }
}

So, currently:

  • The base path of the json appsettings file is set to the value of the SMUSDI_APPSETTINGS_FOLDER environment variable if the target folder exists;
  • Two appsettings files are added to the list of the configuration providers:

    • appsettings.%SMUSDI_SERVICE_NAME%.json
    • appsettings.%SMUSDI_SERVICE_NAME%_%ASPNETCORE_ENVIRONMENT%.json

The appsetting.json and appsettings/%ASPNETCORE_ENVIRONMENT%.json are shared by a list of services and define common settings. The two added ones contain only settings associated to the current service.

  • The environment variables founded in the configuration properties are expanded by the provider added by the call to EnableEnvironmentVariablesExpansion().

Specs

Feature: Application settings folder selection

The application must load appsettings file either from local folder, or from folder defined by the environment variable
SMUSDI_APPSETTINGS_FOLDER.

Background:
    Given the configuration in current folder
        """
        {
            "folder": "current"
        }
        """
    And the configuration in folder 'sub-folder'
        """
        {
            "folder": "sub-folder"
        }
        """

Scenario: Starting the service with variable SMUSDI_APPSETTINGS_FOLDER not set
    Given the service initialized
    When I start the service
    Then the read folder parameter is "current"

Scenario: Starting the service with variable SMUSDI_APPSETTINGS_FOLDER set to sub-folder
    Given the environment variable "SMUSDI_APPSETTINGS_FOLDER" set to "sub-folder"
    And the service initialized
    When I start the service
    Then the read folder parameter is "sub-folder"
Feature: Specific appsettings file

When a setting is overridden in the appsettings file specific to the current service, this value must be used instead of the
one defined in the shared file.

Scenario: Starting service with a setting overridden in the specific appsettings file
    Given the environment variable "SMUSDI_SERVICE_NAME" set to "myservice"
    And the configuration in current folder
        """
        {
            "folder": "current"
        }
        """
    And the configuration file "appsettings.myservice.json"
        """
        {
            "folder": "anotherone"
        }
        """
    And the service initialized
    When I start the service
    Then the read folder parameter is "anotherone"
Feature: Environment variables expansion in configuration settings

When a property uses an environement variable, the variable must be expanded before being sent to the application.

Scenario: Starting service with an property in appsettings.json using an environment variable
    Given the configuration in current folder
        """
        {
            "serviceUrl": "http://%TARGET_SERVER%:%TARGET_PORT%"
        }
        """
    And the environment variable "TARGET_SERVER" set to "myserver.fr.world"
    And the environment variable "TARGET_PORT" set to "23457"
    And the service initialized
    When I start the service
    Then the value of the config property "serviceUrl" is "http://myserver.fr.world:23457"

Scenario Outline: Property containing an environement variable that references an environement variable
    Given the configuration in current folder
        """
        {
            "serviceUrl": "http://%TARGET_SERVER%:%TARGET_PORT%"
        }
        """
    And the environment variable "ENV" set to "int"
    And the environment variable "SMUSDI_EXPAND_ENV_TWICE" set to "<SMUSDI_EXPAND_ENV_TWICE>"
    And the environment variable "TARGET_SERVER" set to "myserver.%ENV%.fr.world"
    And the environment variable "TARGET_PORT" set to "23457"
    And the service initialized
    When I start the service
    Then the value of the config property "serviceUrl" is "<SERVICE_URL>"

    Examples: 
        | SMUSDI_EXPAND_ENV_TWICE | SERVICE_URL                          |
        |                         | http://myserver.%ENV%.fr.world:23457 |
        | dd                      | http://myserver.%ENV%.fr.world:23457 |
        | True                    | http://myserver.int.fr.world:23457   |
        | False                   | http://myserver.%ENV%.fr.world:23457 |