Environment and Configuration

Accessing environment variables

.NET provides access to environment variables via the System.Environment.GetEnvironmentVariable method. This method retrieves the value of an environment variable at runtime.

using System;

const string name = "EXAMPLE_VARIABLE";

var value = Environment.GetEnvironmentVariable(name);
if (string.IsNullOrEmpty(value))
    Console.WriteLine($"Variable '{name}' not set.");
else
    Console.WriteLine($"Variable '{name}' set to '{value}'.");

Rust provides the same environment variable access functionality at runtime via the var and var_os functions from the std::env module.

The var function will return a Result<String, VarError>, and either returns the variable if it is set or returns an error if the variable is either not set or is not valid Unicode.

var_os has a different signature giving back an Option<OsString>, either returning some value if the variable is set, or returning None if the variable is not set. An OsString is not required to be valid Unicode.

use std::env;


fn main() {
    let key = "ExampleVariable";
    match env::var(key) {
        Ok(val) => println!("{key}: {val:?}"),
        Err(e) => println!("couldn't interpret {key}: {e}"),
    }
}
use std::env;

fn main() {
    let key = "ExampleVariable";
    match env::var_os(key) {
        Some(val) => println!("{key}: {val:?}"),
        None => println!("{key} not defined in the enviroment"),
    }
}

Rust also provides environment variable access functionality at compile time. The env! macro from std::env expands the value of the variable at compile time, returning a &'static str. If the variable is not set, an error is emitted.

use std::env;

fn main() {
    let example = env!("ExampleVariable");
    println!("{example}");
}

In .NET compile time access to environment variables can be achieved, albeit in a less straightforward way, via source generators.

Configuration

Configuration in .NET is possible with configuration providers. The framework provides several provider implementations via Microsoft.Extensions.Configuration namespace and NuGet packages.

Configuration providers read configuration data from key-value pairs using different sources and provide a unified view of the configuration via the IConfiguration type.

using Microsoft.Extensions.Configuration;

class Example {
    static void Main()
    {
        IConfiguration configuration = new ConfigurationBuilder()
            .AddEnvironmentVariables()
            .Build();

        var example = configuration.GetValue<string>("ExampleVar");

        Console.WriteLine(example);
    }
}

Other provider examples can be found in the official documentation Configurations provider in .NET.

A similar configuration experience in Rust is available via use of third-party crates such as figment or config.

See the following example making use of config crate:

use config::{Config, Environment};

fn main() {
    let builder = Config::builder().add_source(Environment::default());

    match builder.build() {
        Ok(config) => {
            match config.get_string("examplevar") {
                Ok(v) => println!("{v}"),
                Err(e) => println!("{e}")
            }
        },
        Err(_) => {
            // something went wrong
        }
    }
}