Skip to content

2.2 Configuration

Marjan Nikolovski edited this page Apr 9, 2021 · 1 revision

Purpose

Configuration is used to manage various settings that define an application. The settings are stored in some kind of persistance media that are separate from out application code. In this way we can configure settings independently from our code. Generally an application contains a single persistance media. However there can be many configuration media that manage settings at various levels within an application.

Signals offers multiple implementations for the Configuration aspect out of the box:

  • Signals.Aspects.Configuration.File
  • Signals.Aspects.Configuration.MsSql

Both implementations can be active in the same time.

How to use

File example in file application.config.json:

{
    "ApplicationName": "My application"
}
// Configuration element
public class ApplicationConfiguration
{
    //Configuration key
    public override string Key { get; }

    //Application name, e.g. Facebook website
    [Required]
    public string ApplicationName { get; set; }
}

We define our configuration element by inheriting from Signals.Aspects.Configuration.BaseConfiguration

// Configuration element
public class ApplicationConfiguration : BaseConfiguration<ApplicationConfiguration>
{
    //Configuration key
    public override string Key { get; }

    //Application name, e.g. Facebook website
    [Required]
    public string ApplicationName { get; set; }
}

After we configure our configuration element (confugraiton example below) we can access it by its static instance

// in some part of out application we access the configuration instance
public string GetApplicationNameFromConfiguration()
{
    var applicationName = ApplicationConfiguration.Instance.ApplicationName;
    return applicationName;
}

If the configuration is loaded from database using our database provider, we can update the value as well.

// in some part of out application we update the configuration instance
public void UpdateApplicationName(string applicationName)
{
    ApplicationConfiguration.Instance.ApplicationName = applicationName;
    ApplicationConfiguration.Update(ApplicationConfiguration.Instance);
}

Updated configuration is automatically reloaded from database.

Configuration

We configure the configuration elements by using their static function UseProvider() where we pass either FileConfigurationProvider or MsSqlConfigurationProvider for reading configuration from files and database respectively in the application startup.

Properties explanation

FileConfigurationProvider

  • File: Name of file
  • Path: Path to file
  • ReloadOnAccess: if true, the configuration element will load fresh data from the configuration file, else it will provide cached data

MsSqlConfigurationProvider

  • ConnectionString: Connection string to database that holds the configuration
  • TableName: Table in database that the configuration is stored in
  • KeyColumnName: Column name of Key property
  • ValueColumnName: Column name of Value property
  • ReloadOnAccess: If true, the configuration element will load fresh data from the database, else it will provide cached data

Examples

Using Signals.Aspects.Configuration.File

public static IServiceProvider AddSignals(this IServiceCollection services)
{
    FileConfigurationProvider ProviderForFile(string path, string name) => new FileConfigurationProvider
    {
        File = name,
        Path = path,
        ReloadOnAccess = false
    };

    WebApplicationConfiguration.UseProvider(ProviderForFile("example/path/to/", "web.application.config.json"));
    DatabaseConfiguration.UseProvider(ProviderForFile("example/path/to/", "database.config.json"));
    ApplicationConfiguration.UseProvider(ProviderForFile("example/path/to/", "application.config.json"));


    // Signals configuration...
}

Using Signals.Aspects.Configuration.MsSql

public static IServiceProvider AddSignals(this IServiceCollection services)
{
    MsSqlConfigurationProvider ProviderForDatabase() => new MsSqlConfigurationProvider(myConnectionString)
    {
        TableName = "Configuration",
        ReloadOnAccess = false,
        KeyColumnName = "Key",
        ValueColumnName = "Value"
    };

    WebApplicationConfiguration.UseProvider(ProviderForDatabase());
    DatabaseConfiguration.UseProvider(ProviderForDatabase());
    ApplicationConfiguration.UseProvider(ProviderForDatabase());


    // Signals configuration...
}

Using both

public static IServiceProvider AddSignals(this IServiceCollection services)
{
    FileConfigurationProvider ProviderForFile(string path, string name) => new FileConfigurationProvider
    {
        File = name,
        Path = path,
        ReloadOnAccess = false
    };

    MsSqlConfigurationProvider ProviderForDatabase()
            => new MsSqlConfigurationProvider(DatabaseConfiguration.Instance.ConnectionString)
    {
        TableName = "Configuration",
        ReloadOnAccess = false,
        KeyColumnName = "Key",
        ValueColumnName = "Value"
    };

    WebApplicationConfiguration.UseProvider(ProviderForFile("example/path/to/", "web.application.config.json"));
    DatabaseConfiguration.UseProvider(ProviderForFile("example/path/to/", "database.config.json"));
    ApplicationConfiguration.UseProvider(ProviderForFile("example/path/to/", "application.config.json"));

    DomainConfiguration.UseProvider(ProviderForDatabase());
    IntegrationConfiguration.UseProvider(ProviderForDatabase());


    // Signals configuration...
}

Extending configuration

  1. Install package Signals.Aspects.Configuration
  2. Create class with implementation of Signals.Aspects.Configuration.IConfigurationProvider
/// <summary>
/// Configuration provider
/// </summary>
public class MyConfigurationProvider : IConfigurationProvider
{
    /// <summary>
    /// Indicates if the configuration should be reloaded on property access
    /// </summary>
    bool ReloadOnAccess { get; set; }

    /// <summary>
    /// Loads the configuration into memory
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key"></param>
    /// <returns></returns>
    BaseConfiguration<T> Load<T>(string key) where T : BaseConfiguration<T>, new();

    /// <summary>
    /// Reloads the configuration
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key"></param>
    /// <returns></returns>
    BaseConfiguration<T> Reload<T>(string key) where T : BaseConfiguration<T>, new();

    /// <summary>
    /// Updates the configuration
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="configuration"></param>
    void Update<T>(T configuration) where T : BaseConfiguration<T>, new();
}
  1. Use our implementation of IConfigurationProvider when configuring our application
public static IServiceProvider AddSignals(this IServiceCollection services)
{
    MyConfigurationProvider MyProvider() => new MyConfigurationProvider
    {
    };

    WebApplicationConfiguration.UseProvider(MyProvider());
    DatabaseConfiguration.UseProvider(MyProvider());
    ApplicationConfiguration.UseProvider(MyProvider());

    // Signals configuration...
}
Clone this wiki locally