Last updated

Configuration

Configuration is the process of specifying settings and parameters that control the behavior of an application. The sections below show how to access Configuration settings and to monitor for changes in the configuration at runtime. The SDK constructs the configuration using several sources, as described in the Configuration Sources section.

Accessing Configuration Settings

Configuration setting values are accessed using a singleton and are accessed hierarchically by separating the levels of the hierarchy with colons.

Examples:

All examples use the following configuration:

AEA.json:

{
    "App" : {
        "SomeSetting": true,
        "Fruit": [ "Apple", "Banana", "Pear" ],
        "FruitObjects": [ {"Name": "Apple"}, {"Name": "Banana"}, {"Name": "Pear"}]
    }
}

Retrieving a setting

using static Agora.SDK;
...
Console.Writeline(Config["App:SomeSetting"]);
from agoraiot import config
...
print( config["App:SomeSetting"] )

Retrieving an array

using static Agora.SDK;
using Microsoft.Extensions.Configuration;
...
var fruits = Config.GetSection("App:Fruit").Get<List<string>>();

foreach(var fruit in fruits)
    Console.WriteLine(fruit);
from agoraiot import config

fruits = config["App:Fruit"]

for fruit in fruits:
    print( fruit )

Output:

Apple
Banana
Pear

Accessing array of Objects

[!IMPORTANT] For .NET, one typically deploys containers using single, trimmed executables. Configration binding and autopopulation of object elements can fail at run-time due required code for the functionality is trimmed, making the deployed application run differently than during development. To fix this issue, Microsoft introduced > a project setting that affects .NET 8 to enable auto-generation of binding code.

To enable this feature, add <EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator> to <PropertyGroup> in the csproj files using configuration / objecting binding.

using static Agora.SDK;
using Microsoft.Extensions.Configuration;

class Fruit { public string Name { get; set; } }

List<Fruit> fruits = Config.GetSection("App:FruitObjects").Get<List<Fruit>>();

foreach(var fruit in fruits)
    Console.WriteLine(fruit.Name);

// example using binding

List<Fruit> fruits = [];

Config.GetSection("App:FruitObjects").Bind(fruits);
from agoraiot import config

class Fruit:
    def __init__(self, name):
        self.name = name

fruits = config["App:FruitObjects"]

for fruitdata in fruits
    fruit = Fruit(fruitdata["Name"])

# to deserialize directly you will need to create custom json encoders/decoders

Setting Default Configuration Settings and Overrides

The configuration is built from a set of sources that starts with Defaults and ends with Overrides as shown in Configuration Overview.
To set defaults or overrides use the Defaults or Overrides dictionaries.

Example:

using static Agora.SDK;

...
Config.Defaults["App:SettingName"] = "Default value if none provided";
Config.Overrides["App:OtherSettingName"] = "Overrides all other sources";
Config.Build();
from agoraiot import config

...
config.defaults["App:SettingName"] = "Default value if none provided";
config.overrides["App:OtherSettingName"] = "Overrides all other sources";
config.build()

Runtime Configuration Changes

The alternate configuration and any Key-Per-File settings allow application settings to be modified while the application is running. An application should monitor the Configuration (as a whole) or an individual settings has changed if a run-time change is allowed.

Monitoring for Configuration Changes

    Config.Changed += ConfigChanged;
...
    private void ConfigChanged(object? sender, EventArgs e)
    {
        "Configuration Changed".LogInfo();
    }
def config_change_handler():
    logger.info("Configuration Changed")

config.observe_config( config_change_handler )

Monitoring for Configuration Changes of Individual Settings

var mySetting = Agora.ObservableSetting.Get("AEA2:LogLevel");
mySetting.PropertyChange += SettingChange;

...
private void SettingChange( object? sender, 
                            System.ComponentModel.PropertyChangedEventArgs e)
{
    if (sender is Agora.ObservableSetting o)
        $"Setting Changed to `{o.Value}'".LogInfo();
}
def setting_changed(val):
    logger.info(f"Setting Changed to {val}")

config.observe("AEA2:LogLevel", setting_changed )

Configuration to JSON

using Microsoft.Extensions.Configuration;

var json = Config.SerializeToJson();
if ( json != null )
    json.ToJsonString(new JsonSerializerOptions() { WriteIndented = true }).LogInfo();
from agoraiot import config, logger
import json

logger.info( json.dumps(config, indent=4) )