BITS.Generators.AppSettings 1.0.2

Prefix Reserved
The owner has unlisted this package. This could mean that the package is deprecated, has security vulnerabilities or shouldn't be used anymore.
dotnet add package BITS.Generators.AppSettings --version 1.0.2
                    
NuGet\Install-Package BITS.Generators.AppSettings -Version 1.0.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="BITS.Generators.AppSettings" Version="1.0.2">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="BITS.Generators.AppSettings" Version="1.0.2" />
                    
Directory.Packages.props
<PackageReference Include="BITS.Generators.AppSettings">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add BITS.Generators.AppSettings --version 1.0.2
                    
#r "nuget: BITS.Generators.AppSettings, 1.0.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package BITS.Generators.AppSettings@1.0.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=BITS.Generators.AppSettings&version=1.0.2
                    
Install as a Cake Addin
#tool nuget:?package=BITS.Generators.AppSettings&version=1.0.2
                    
Install as a Cake Tool

BITS.Generators.AppSettings

NuGet Version NuGet Downloads License: MIT

A modern C# source generator that creates strongly-typed, AOT-compatible configuration classes from your appsettings.json files with zero runtime reflection.

โœจ Features

  • ๐Ÿš€ Zero Runtime Overhead - All code generated at compile time
  • ๐ŸŽฏ Strongly-Typed - Full IntelliSense and compile-time type checking
  • โšก AOT Compatible - Works perfectly with Native AOT for maximum performance
  • ๐Ÿ”— JSON Pointer Resolution - Reference values with $ConnectionStrings:Primary syntax
  • ๐Ÿ” Compile-Time Validation - Analyzer detects missing configuration at build time
  • ๐Ÿ“ฆ Easy Integration - Drop in and start using immediately
  • ๐Ÿงฉ Nested Sections - Support for complex hierarchical configuration
  • ๐ŸŽจ Flexible Mapping - Custom JSON paths and section names

๐Ÿ“ฆ Installation

Install via NuGet Package Manager:

dotnet add package BITS.Generators.AppSettings

Or via Package Manager Console:

Install-Package BITS.Generators.AppSettings

๐Ÿš€ Quick Start

Step 1: Define Your Configuration Interface

Create an interface and mark it with [AppSettings]:

using BITS.Generators.AppSettings;

[AppSettings]
public interface IDatabaseConfig
{
    string ConnectionString { get; }
    int MaxRetries { get; }
    int Timeout { get; }
}

Step 2: Add Configuration to appsettings.json

{
  "Database": {
    "ConnectionString": "Server=localhost;Database=MyApp;",
    "MaxRetries": 3,
    "Timeout": 30
  }
}

Step 3: Register and Use Configuration

The generator creates extension methods for easy registration:

// โœ… Recommended: Use generated extension method
services.AddAppSettings(configuration);

// Or register individual configurations
services.AddDatabaseConfig(configuration);

The generator also creates a Create() method for manual binding:

// Alternative: Manual binding (also AOT-compatible)
var databaseConfig = DatabaseConfig.Create(configuration, "Database");
services.AddSingleton<IDatabaseConfig>(databaseConfig);

๐ŸŽฏ What Gets Generated

For the interface above, the generator creates:

/// <summary>
/// Strongly-typed configuration for Database section.
/// Generated from IDatabaseConfig interface.
/// </summary>
public sealed record DatabaseConfig(
    string ConnectionString,
    int MaxRetries,
    int Timeout
) : IDatabaseConfig
{
    /// <summary>
    /// Creates a new instance from IConfiguration.
    /// </summary>
    public static DatabaseConfig Create(
        IConfiguration configuration, 
        string? sectionOverride = null)
    {
        var section = configuration.GetSection(sectionOverride ?? "Database");
        
        return new DatabaseConfig(
            ConnectionString: ConfigurationHelper.GetValueFromSection<string>(
                configuration, section, "ConnectionString", isRequired: true),
            MaxRetries: ConfigurationHelper.GetValueFromSection<int>(
                configuration, section, "MaxRetries", isRequired: true),
            Timeout: ConfigurationHelper.GetValueFromSection<int>(
                configuration, section, "Timeout", isRequired: true)
        );
    }
}

Extension Methods for Dependency Injection

The generator automatically creates extension methods for easy service registration:

Register Individual Configurations

// Register a specific configuration
services.AddDatabaseConfig(configuration);
services.AddLoggingConfig(configuration);

Register All Configurations

// Register only ROOT-level configurations (default behavior)
// Root configs are those NOT referenced by [Section] attributes in other configs
services.AddAppSettings(configuration);

// Register ALL configurations including nested subsections
services.AddAppSettings(configuration, registerNested: true);

When to use registerNested: true?

  • Default (registerNested: false): Use when you only want root-level configs in DI container

    • Example: Register IDatabaseConfig but NOT IFeaturesConfig or IConnectionStringsConfig (if they're nested)
    • Nested configs are still accessible via their parent properties
  • registerNested: true: Use when you want ALL configs available for injection

    • Example: Inject IFeaturesConfig directly without going through IDatabaseConfig.Features
    • Useful for modular architectures where components need direct access to subsections

Example:

// Configuration interfaces
[AppSettings]
public interface IDatabaseConfig
{
    string Host { get; }
    int Port { get; }
    
    [Section("Database:Features")]
    IFeaturesConfig Features { get; }  // โ† IFeaturesConfig is NESTED
}

[AppSettings]
public interface IFeaturesConfig
{
    bool CacheEnabled { get; }
}

// Service registration
services.AddAppSettings(configuration);  // Only IDatabaseConfig registered
// Access: dbConfig.Features.CacheEnabled โœ“

services.AddAppSettings(configuration, registerNested: true);  // Both registered
// Access: featuresConfig.CacheEnabled โœ“

๏ฟฝ๐Ÿ”ฅ Advanced Features

Smart Section Names

No need to specify section names - they're automatically derived:

[AppSettings]  // Section: "Database" (strips "I" and "Config")
public interface IDatabaseConfig { }

[AppSettings]  // Section: "Logging" (strips "I" and "Settings")
public interface ILoggingSettings { }

[AppSettings]  // Section: "Features" (strips "I", "Config", and "s")
public interface IFeaturesConfigs { }

Auto-stripped suffixes: Settings, Setting, Configs, Config, Configuration, Configurations

JSON Pointer References

Reuse configuration values with JSON pointers using $ prefix:

{
  "ConnectionStrings": {
    "Primary": "Server=primary-db;Database=MainDB;",
    "Secondary": "$ConnectionStrings:Primary",
    "Backup": "$ConnectionStrings:Secondary"
  }
}
[AppSettings]
public interface IConnectionStrings
{
    string Primary { get; }
    string Secondary { get; }   // Resolves to Primary value
    string Backup { get; }      // Resolves to Secondary (which resolves to Primary)
}

Nested Subsections

Handle complex nested configurations:

[AppSettings]
public interface IDatabaseConfig
{
    string Host { get; }
    int Port { get; }
    
    [Section("Database:Features")]
    IFeaturesConfig Features { get; }
    
    [Section("Database:ConnectionStrings")]
    IConnectionStrings ConnectionStrings { get; }
}

[AppSettings]
public interface IFeaturesConfig
{
    bool CacheEnabled { get; }
    int CacheExpiration { get; }
}

Interface Inheritance

Configuration interfaces can inherit from base interfaces:

// Base configuration interface (not marked with [AppSettings])
public interface IBaseConfig
{
    string Environment { get; }
    bool EnableLogging { get; }
}

// Application configuration inheriting from base
[AppSettings(Section = "App")]
public interface IAppConfig : IBaseConfig
{
    string AppName { get; }
    string Version { get; }
}

appsettings.json:

{
  "App": {
    "Environment": "Production",
    "EnableLogging": true,
    "AppName": "MyApplication",
    "Version": "1.0.0"
  }
}

Generated code includes all properties:

public sealed record AppConfig(
    string Environment,      // From IBaseConfig
    bool EnableLogging,      // From IBaseConfig
    string AppName,          // From IAppConfig
    string Version           // From IAppConfig
) : IAppConfig, IBaseConfig  // Implements both interfaces
{
    public static AppConfig Create(IConfiguration configuration, string? sectionOverride = null)
    {
        // Binds all properties from App section
    }
}

Use with inheritance and subsections:

[AppSettings(Section = "App")]
public interface IAppConfig : IBaseConfig
{
    string AppName { get; }
    
    // Nested subsection
    [Section("Database:Credentials")]
    IDatabaseCredentials Credentials { get; }
}

[AppSettings(Section = "Database:Credentials")]
public interface IDatabaseCredentials
{
    string Username { get; }
    string Password { get; }
}

Custom JSON Paths

Map properties to specific JSON locations:

[AppSettings]
public interface IAppConfig
{
    [JsonPath("ConnectionStrings:Default")]
    string DefaultConnection { get; }
    
    [JsonPath("App:Name")]
    string ApplicationName { get; }
    
    string Version { get; }  // Maps to AppConfig:Version by default
}

Optional (Nullable) Properties

Support for nullable types:

[AppSettings]
public interface IOptionalConfig
{
    string RequiredValue { get; }      // Must be in appsettings.json
    string? OptionalValue { get; }     // Can be null or missing
    int? OptionalNumber { get; }       // Can be null or missing
}

Parent Sections

Organize configuration with parent-child relationships:

[AppSettings(ParentSection = "Logging")]
public interface ILogLevelConfig
{
    string Default { get; }
    string System { get; }
}

Maps to:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "System": "Warning"
    }
  }
}

๐Ÿ” Compile-Time Validation

The built-in analyzer (BITS_APP_SETTINGS) validates your configuration at build time:

[AppSettings]
public interface IDatabaseConfig
{
    string ConnectionString { get; }
    int MaxRetries { get; }
}

If appsettings.json is missing MaxRetries:

error BITS_APP_SETTINGS: Configuration section 'Database' is missing required properties: MaxRetries

Configure severity in .editorconfig:

# Make it a warning instead of error
dotnet_diagnostic.BITS_APP_SETTINGS.severity = warning

# Or disable it
dotnet_diagnostic.BITS_APP_SETTINGS.severity = none

โšก AOT Compatibility

Fully compatible with Native AOT - no reflection required:

// โœ… AOT-compatible - uses generated code
var config = DatabaseConfig.Create(configuration, "Database");

// โŒ Not AOT-compatible - uses reflection
var config = configuration.GetSection("Database").Get<DatabaseConfig>();

Supported Types (AOT-Compatible)

All conversions are handled without reflection:

  • Primitives: string, bool, int, long, double, decimal, float
  • Unsigned: uint, ulong, ushort, byte, sbyte
  • Date/Time: DateTime, DateTimeOffset, TimeSpan
  • Other: Guid, enum types
  • Nullable: All above types as Nullable<T> or T?

๐Ÿ“š Complete Example

appsettings.json:

{
  "Database": {
    "Host": "localhost",
    "Port": 5432,
    "ConnectionString": "Server=$Database:Host;Port=$Database:Port;Database=MyApp",
    "Features": {
      "CacheEnabled": true,
      "CacheExpiration": 300
    }
  },
  "Logging": {
    "Level": "Information",
    "EnableConsole": true
  }
}

Configuration Interfaces:

[AppSettings]
public interface IDatabaseConfig
{
    string Host { get; }
    int Port { get; }
    string ConnectionString { get; }  // Resolves $Database:Host and $Database:Port
    
    [Section("Database:Features")]
    IFeaturesConfig Features { get; }
}

[AppSettings]
public interface IFeaturesConfig
{
    bool CacheEnabled { get; }
    int CacheExpiration { get; }
}

[AppSettings]
public interface ILoggingConfig
{
    string Level { get; }
    bool EnableConsole { get; }
}

Usage:

var builder = WebApplication.CreateBuilder(args);

// Register configurations
builder.Services.AddSingleton<IDatabaseConfig>(
    DatabaseConfig.Create(builder.Configuration, "Database"));
    
builder.Services.AddSingleton<ILoggingConfig>(
    LoggingConfig.Create(builder.Configuration, "Logging"));

var app = builder.Build();

// Use in your services
public class MyService
{
    private readonly IDatabaseConfig _dbConfig;
    
    public MyService(IDatabaseConfig dbConfig)
    {
        _dbConfig = dbConfig;
    }
    
    public void DoWork()
    {
        Console.WriteLine($"Connecting to {_dbConfig.Host}:{_dbConfig.Port}");
        Console.WriteLine($"Cache enabled: {_dbConfig.Features.CacheEnabled}");
    }
}

๐Ÿ› ๏ธ Requirements

  • .NET 10 SDK or later
  • C# 14 or later
  • Works with: Console Apps, ASP.NET Core, Worker Services, etc.

๐Ÿ“– API Reference

[AppSettings] Attribute

Marks an interface for configuration generation.

Properties:

  • Section (optional): Configuration section name (default: auto-derived from interface name)
  • ParentSection (optional): Parent section path

Example:

[AppSettings(Section = "CustomName", ParentSection = "Parent")]
public interface IMyConfig { }

[JsonPath] Attribute

Specifies a custom JSON path for a property.

Example:

[JsonPath("Nested:Deep:Value")]
string MyProperty { get; }

[Section] Attribute

Alternative to [JsonPath] for specifying section paths on properties.

Example:

[Section("Database:Advanced")]
IAdvancedConfig Advanced { get; }

๐Ÿงช Testing

The project includes comprehensive tests using TUnit:

# Run all tests
dotnet test

# Run with detailed output
dotnet test --verbosity detailed

๐Ÿ“ฆ Samples

Check out the samples/ directory for complete working examples:

  • AppSettingsConsole - Basic usage with DI
  • AdvancedFeaturesExample - Nested sections and pointer resolution
  • InheritanceExample - Interface inheritance patterns
# Run the advanced example
dotnet run --project samples/AdvancedFeaturesExample

๐Ÿค Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new features
  4. Ensure all tests pass
  5. Follow the existing code style (see .editorconfig)
  6. Submit a pull request

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿ™ Acknowledgments

๐Ÿ“ž Support


Made with โค๏ธ by Blue IT Systems

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated

See CHANGELOG.md for detailed release notes.