Skip to content

A simple, flexible, and readable .NET configuration library with pluggable providers for environment variables, JSON, and more.

License

Notifications You must be signed in to change notification settings

Dzeta-tech/configuration

Repository files navigation

πŸ› οΈ Dzeta.Configuration

NuGet Version NuGet Downloads Build Status .NET Version License GitHub Stars

A simple, flexible, and readable .NET configuration library with pluggable providers for environment variables, JSON, and more.

πŸ“‹ Table of Contents

✨ Features

  • πŸš€ Simple: Clean, minimal API
  • 🎯 Type-safe: Strong typing with validation
  • πŸ”§ Flexible: Support for simple types and nested objects
  • πŸ“¦ DI Ready: Seamless dependency injection integration
  • βœ… Validated: Built-in validation using data annotations
  • πŸ—‚οΈ Nested: Full support for nested configuration objects
  • πŸ—οΈ Extensible: Pluggable provider architecture
  • 🎨 Clean: Beautiful, readable code

πŸ“¦ Installation

dotnet add package Dzeta.Configuration

πŸš€ Quick Start

1. Define Configuration Classes

public class ApplicationConfiguration : BaseConfiguration
{
    [Required]
    public string ApiKey { get; set; } = string.Empty;

    [DefaultValue(8080)]
    public int Port { get; set; }

    [Required]
    public DatabaseConnectionConfiguration Database { get; set; } = new();

    public bool Debug { get; set; }
}

2. Set Environment Variables

export MYAPP_APIKEY=your-secret-key
export MYAPP_PORT=9000
export MYAPP_DEBUG=true
export MYAPP_DATABASE_HOST=localhost
export MYAPP_DATABASE_PORT=5432
export MYAPP_DATABASE_USERNAME=user
export MYAPP_DATABASE_PASSWORD=password
export MYAPP_DATABASE_DATABASE=mydb

3. Register with Dependency Injection

// Program.cs
var builder = WebApplication.CreateBuilder(args);

// First, setup the configuration provider
builder.Services.UseEnvironmentConfigurationProvider("MYAPP");

// Then, register your configuration classes
builder.Services.AddConfiguration<ApplicationConfiguration>();

var app = builder.Build();

4. Use in Your Application

public class ApiController : ControllerBase
{
    private readonly ApplicationConfiguration _config;

    public ApiController(ApplicationConfiguration config)
    {
        _config = config;
    }

    public IActionResult GetStatus()
    {
        return Ok(new 
        {
            ApiKey = _config.ApiKey.Substring(0, 4) + "***",
            Port = _config.Port,
            Debug = _config.Debug,
            DatabaseConnection = _config.Database.ConnectionString
        });
    }
}

πŸ—οΈ Advanced Usage

Direct Usage

var configuration = new ConfigurationBuilder()
    .AddEnvironmentVariables()
    .Build();

var valueProvider = new EnvironmentValueProvider(configuration, "MYAPP");
var populator = new ConfigurationPopulator(valueProvider);

var config = new ApplicationConfiguration();
populator.Populate(config);
populator.Validate(config);

Console.WriteLine($"Database: {config.Database.ConnectionString}");

Custom Providers

// Register a custom provider
builder.Services.UseConfigurationProvider(serviceProvider => 
    new MyCustomValueProvider());

// Or combine multiple providers
builder.Services.UseConfigurationProvider(serviceProvider => 
    new CompositeValueProvider(
        new EnvironmentValueProvider(config, "MYAPP"),
        new JsonValueProvider("appsettings.json")
    ));

πŸ”§ Configuration Classes

Simple Properties

All configuration classes must inherit from BaseConfiguration:

public class ServerConfiguration : BaseConfiguration
{
    public string Host { get; set; } = "localhost";
    public int Port { get; set; } = 8080;
    public bool UseHttps { get; set; } = false;
    public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(30);
}

Nested Configurations

Create complex configuration hierarchies with nested objects:

public class ApplicationConfiguration : BaseConfiguration
{
    // Simple properties
    public string ApplicationName { get; set; } = "MyApp";
    public string Version { get; set; } = "1.0.0";
    
    // Nested configurations
    public ServerConfiguration Server { get; set; } = new();
    public DatabaseConnectionConfiguration Database { get; set; } = new();
    public LoggingConfiguration Logging { get; set; } = new();
    public CacheConfiguration Cache { get; set; } = new();
}

public class LoggingConfiguration : BaseConfiguration
{
    public string Level { get; set; } = "Information";
    public bool EnableConsole { get; set; } = true;
    public bool EnableFile { get; set; } = false;
    public string FilePath { get; set; } = "logs/app.log";
}

public class CacheConfiguration : BaseConfiguration
{
    public string Provider { get; set; } = "Memory";
    public TimeSpan DefaultExpiration { get; set; } = TimeSpan.FromMinutes(30);
    public int MaxSize { get; set; } = 1000;
}

Built-in Database Configuration

The library includes a ready-to-use database configuration class:

public class DatabaseConnectionConfiguration : BaseConfiguration
{
    [Required]
    public string Host { get; set; } = string.Empty;

    [DefaultValue(5432)]
    public int Port { get; set; }

    [Required]
    public string Username { get; set; } = string.Empty;

    [Required]
    public string Password { get; set; } = string.Empty;

    [Required]
    public string Database { get; set; } = string.Empty;

    // Auto-generated connection string
    public string ConnectionString => 
        $"Host={Host};Port={Port};Username={Username};Password={Password};Database={Database}";
}

This is just an example of how to create nested configuration classes. You can create your own:

public class RedisConfiguration : BaseConfiguration
{
    public string Host { get; set; } = "localhost";
    public int Port { get; set; } = 6379;
    public string Password { get; set; } = string.Empty;
    public int Database { get; set; } = 0;
    
    public string ConnectionString => 
        $"{Host}:{Port},password={Password},defaultDatabase={Database}";
}

public class EmailConfiguration : BaseConfiguration
{
    public string SmtpHost { get; set; } = string.Empty;
    public int SmtpPort { get; set; } = 587;
    public string Username { get; set; } = string.Empty;
    public string Password { get; set; } = string.Empty;
    public bool UseSsl { get; set; } = true;
}

πŸ“ Environment Variable Naming

Environment variables are automatically mapped from nested property paths (camelCase to snake_case):

Configuration Path Environment Variable Example Value
ApiKey MYAPP_API_KEY secret123
Server.Host MYAPP_SERVER_HOST localhost
Server.Port MYAPP_SERVER_PORT 8080
Database.Host MYAPP_DATABASE_HOST db.example.com
Database.Port MYAPP_DATABASE_PORT 5432
Logging.Level MYAPP_LOGGING_LEVEL Debug
Cache.MaxSize MYAPP_CACHE_MAXSIZE 2000

Naming Rules:

  • Property names are converted to UPPERCASE
  • Nested objects use underscore (_) as separator
  • Prefix is added at the beginning if specified

βœ… Validation

Use data annotations for automatic validation:

public class ApiConfiguration : BaseConfiguration
{
    [Required]
    [EmailAddress]
    public string AdminEmail { get; set; } = string.Empty;

    [Required]
    [StringLength(50, MinimumLength = 8)]
    public string ApiKey { get; set; } = string.Empty;

    [Range(1000, 65535)]
    [DefaultValue(8080)]
    public int Port { get; set; }

    [Url]
    public string BaseUrl { get; set; } = "https://api.example.com";
}

If validation fails, a ConfigurationValidationException is thrown with detailed error information.

πŸ”— Supported Types

  • Primitives: int, long, double, bool, byte, short, etc.
  • Common types: string, decimal, DateTime, TimeSpan, Uri, Guid
  • Nullable types: int?, DateTime?, etc.
  • Enums: Any enum type (parsed case-insensitive)
  • Nested objects: Classes inheriting from BaseConfiguration
public enum LogLevel { Debug, Information, Warning, Error }

public class ExampleConfiguration : BaseConfiguration
{
    public string Name { get; set; } = string.Empty;
    public int Count { get; set; }
    public bool Enabled { get; set; }
    public DateTime CreatedAt { get; set; }
    public TimeSpan Timeout { get; set; }
    public Uri Website { get; set; } = new("https://example.com");
    public Guid Id { get; set; }
    public LogLevel Level { get; set; } = LogLevel.Information;
    public int? OptionalNumber { get; set; }
}

πŸ›οΈ Architecture

The library follows a clean, modular architecture:

 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚   ServiceCollection   β”‚
 β”‚      Extensions       β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
            β”‚
            β–Ό
 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚ IConfigurationValue   β”‚
 β”‚      Provider         β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
            β”‚
            β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  ConfigurationPopulator β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
            β”‚
            β–Ό
 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚   BaseConfiguration   β”‚
 β”‚       Classes         β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Components:

  • IConfigurationValueProvider: Interface for value sources
  • EnvironmentValueProvider: Reads from environment variables
  • ConfigurationPopulator: Fills objects from providers
  • BaseConfiguration: Base class for all configurations

This architecture allows easy extension with new providers (JSON, Database, etc.) without changing existing code.

πŸ“„ License

MIT License - feel free to use in your projects!

About

A simple, flexible, and readable .NET configuration library with pluggable providers for environment variables, JSON, and more.

Resources

License

Stars

Watchers

Forks

Languages