VYaml.Configuration
1.0.0
dotnet add package VYaml.Configuration --version 1.0.0
NuGet\Install-Package VYaml.Configuration -Version 1.0.0
<PackageReference Include="VYaml.Configuration" Version="1.0.0" />
<PackageVersion Include="VYaml.Configuration" Version="1.0.0" />
<PackageReference Include="VYaml.Configuration" />
paket add VYaml.Configuration --version 1.0.0
#r "nuget: VYaml.Configuration, 1.0.0"
#:package VYaml.Configuration@1.0.0
#addin nuget:?package=VYaml.Configuration&version=1.0.0
#tool nuget:?package=VYaml.Configuration&version=1.0.0
VYaml.Configuration
High-performance YAML configuration for .NET — built on VYaml's streaming parser with full YAML 1.2 support
VYaml.Configuration seamlessly integrates YAML files into .NET's configuration pipeline, enabling human-readable configuration that works exactly like the built-in JSON provider. Perfect for microservices, CLI tools, and any application requiring intuitive configuration management.
Quick Start
Install the package:
# .NET CLI
dotnet add package VYaml.Configuration
# Package Manager
Install-Package VYaml.Configuration
# PackageReference
<PackageReference Include="VYaml.Configuration" Version="1.0.0" />
Add YAML configuration in 30 seconds:
// Program.cs or Startup.cs
var builder = WebApplication.CreateBuilder(args);
// Add your YAML configuration file
builder.Configuration.AddYamlFile("appsettings.yaml", optional: false);
var app = builder.Build();
// Access configuration values immediately
var serverUrl = app.Configuration["server:url"];
Console.WriteLine($"Server configured at: {serverUrl}");
Your appsettings.yaml
:
# Server configuration
server:
url: https://api.example.com
timeout: 30
retries: 3
Drop-in Replacement
VYaml.Configuration works exactly like the built-in JSON configuration provider:
// Before - JSON configuration
builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
// After - YAML configuration
builder.Configuration.AddYamlFile("appsettings.yaml", optional: false, reloadOnChange: true);
All features work identically:
- Same configuration path syntax (
section:subsection:value
) - Same binding to POCO objects
- Same environment-specific file patterns
- Same reload-on-change support
- Same integration with Options pattern
Why VYaml.Configuration?
High-performance streaming parser — Built on VYaml for efficient YAML processing
Drop-in replacement — Works exactly like the built-in JSON configuration provider
Full YAML 1.2 compliance — Support for all YAML features including multi-line strings, comments, and complex structures
Hot reload support — Automatic configuration updates without application restart
Type-safe binding — Seamless integration with .NET's Options pattern and validation
Schema validation — JSON Schema support for YAML validation and IntelliSense
Production ready — Comprehensive error handling and diagnostics
AOT compatible — Full support for Native AOT and trimming scenarios
Features
Core Capabilities
- Hierarchical configuration with dot-notation access (
server:database:connectionString
) - Array and sequence support with automatic index mapping
- Environment-specific files (
appsettings.{Environment}.yaml
) - Configuration composition from multiple sources with proper precedence
- Change notifications via
IOptionsMonitor<T>
- Validation integration with data annotations and custom validators
- JSON Schema support for validation and IDE IntelliSense
YAML 1.2 Features
- Block scalars for multi-line content (
|
and>
) - Proper boolean handling (
true
/false
, notyes
/no
) - Comments for documentation
- UTF-8 support without BOM requirement
- Consistent null value handling
Comprehensive Usage
Configuration Binding
Strongly-typed configuration with validation:
// ServerOptions.cs - Define your configuration model
public class ServerOptions
{
// URL must be provided and valid
[Required]
[Url]
public string Url { get; set; }
// Timeout between 1 and 300 seconds
[Range(1, 300)]
public int Timeout { get; set; } = 30;
// Maximum retry attempts
[Range(0, 10)]
public int Retries { get; set; } = 3;
}
// Program.cs - Register with DI container
builder.Services.Configure<ServerOptions>(
builder.Configuration.GetSection("server"))
.AddOptionsWithValidateOnStart<ServerOptions>();
// ApiService.cs - Consume in your services
public class ApiService
{
private readonly ServerOptions _options;
// Options injected by DI container
public ApiService(IOptions<ServerOptions> options)
{
_options = options.Value;
}
// Use configuration in your methods
public async Task<string> CallApiAsync()
{
// Access strongly-typed configuration
var client = new HttpClient { Timeout = TimeSpan.FromSeconds(_options.Timeout) };
return await client.GetStringAsync(_options.Url);
}
}
Complex Hierarchical Configuration
# appsettings.yaml - Full application configuration
# Application metadata
application:
name: MyService
version: 2.0.0
# Feature flags and settings
features:
# Authentication configuration
authentication:
providers:
- name: AzureAD
enabled: true
clientId: ${AZURE_CLIENT_ID} # Environment variable substitution
- name: Google
enabled: false
# Rate limiting configuration
rateLimit:
requests: 100
window: 60 # seconds
# Database connections
database:
connections:
# Primary read-write connection
primary:
server: localhost
port: 5432
database: myapp
# Read-only replica
readonly:
server: localhost-replica
port: 5432
database: myapp
Access nested configuration:
// Program.cs - Multiple ways to access configuration
// Method 1: Bind to strongly-typed list
var authProviders = Configuration
.GetSection("features:authentication:providers")
.Get<List<AuthProvider>>();
// Method 2: Register entire section with DI
services.Configure<DatabaseOptions>(
Configuration.GetSection("database"));
// Method 3: Direct access for simple values
var rateLimitRequests = Configuration.GetValue<int>("features:rateLimit:requests");
Environment-Specific Configuration
// Program.cs - Layer configuration files by environment
builder.Configuration
// Base configuration - always loaded
.AddYamlFile("appsettings.yaml", optional: false, reloadOnChange: true)
// Environment-specific overrides (Development, Staging, Production)
.AddYamlFile($"appsettings.{builder.Environment.EnvironmentName}.yaml",
optional: true, reloadOnChange: true)
// Local developer overrides - not in source control
.AddYamlFile("appsettings.local.yaml",
optional: true, reloadOnChange: true);
Integration with Other Providers
VYaml.Configuration works seamlessly with all other configuration providers:
// Program.cs - Combine multiple configuration sources
var builder = WebApplication.CreateBuilder(args);
builder.Configuration
// 1. Start with JSON base configuration
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true)
// 2. Layer YAML configuration (overrides JSON)
.AddYamlFile("appsettings.yaml", optional: true, reloadOnChange: true)
.AddYamlFile($"appsettings.{builder.Environment.EnvironmentName}.yaml", optional: true)
// 3. User secrets for development
.AddUserSecrets<Program>(optional: true)
// 4. Environment variables
.AddEnvironmentVariables()
// 5. Command line arguments (highest priority)
.AddCommandLine(args);
// Configuration is merged in order - later sources override earlier ones
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
Priority order (highest to lowest):
- Command line arguments
- Environment variables
- User secrets (Development only)
appsettings.{Environment}.yaml
appsettings.yaml
appsettings.{Environment}.json
appsettings.json
Configuration Validation
VYaml.Configuration provides comprehensive validation support through the Options pattern:
// Models/AppConfiguration.cs - Define your configuration models
public class AppConfiguration
{
[Required]
public DatabaseSettings Database { get; set; }
[Required]
public ApiSettings Api { get; set; }
}
public class DatabaseSettings : IValidatableObject
{
[Required]
public string ConnectionString { get; set; }
[Range(1, 100)]
public int MaxConnections { get; set; } = 10;
[Range(1, 300)]
public int CommandTimeout { get; set; } = 30;
// Custom validation logic
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (ConnectionString?.Contains("Production") == true && MaxConnections < 20)
{
yield return new ValidationResult(
"Production database requires at least 20 connections",
new[] { nameof(MaxConnections) });
}
}
}
public class ApiSettings
{
[Required, Url]
public string BaseUrl { get; set; }
[Required]
public string ApiKey { get; set; }
[EmailAddress]
public string SupportEmail { get; set; }
}
// Program.cs - Configure validation
builder.Services
// Basic registration with validation
.Configure<AppConfiguration>(builder.Configuration)
.ValidateDataAnnotations()
// Validate on startup (fail fast)
.ValidateOnStart();
// Advanced validation with custom validators
builder.Services.AddSingleton<IValidateOptions<ApiSettings>, ApiSettingsValidator>();
// Validators/ApiSettingsValidator.cs
public class ApiSettingsValidator : IValidateOptions<ApiSettings>
{
public ValidateOptionsResult Validate(string name, ApiSettings options)
{
if (options.BaseUrl.StartsWith("https://") && !options.BaseUrl.Contains("localhost"))
{
return ValidateOptionsResult.Fail("API must use HTTPS in production");
}
if (options.ApiKey.Length < 32)
{
return ValidateOptionsResult.Fail("API key must be at least 32 characters");
}
return ValidateOptionsResult.Success;
}
}
Validation at different stages:
// 1. Startup validation (recommended)
builder.Services.AddOptionsWithValidateOnStart<AppConfiguration>()
.Bind(builder.Configuration);
// 2. First-use validation
public class MyService
{
public MyService(IOptions<AppConfiguration> options)
{
// Throws if validation fails on first access
var config = options.Value;
}
}
// 3. Runtime validation with monitoring
public class DynamicService
{
public DynamicService(IOptionsMonitor<AppConfiguration> monitor)
{
monitor.OnChange(config =>
{
// Validation runs automatically on configuration changes
Console.WriteLine("Configuration updated and validated");
});
}
}
Example configuration file with validation:
# appsettings.yaml - Configuration that matches validation rules
database:
connectionString: "Server=localhost;Database=myapp;Integrated Security=true"
maxConnections: 50 # Must be 1-100
commandTimeout: 30 # Must be 1-300 seconds
api:
baseUrl: https://api.example.com # Must be valid URL with HTTPS
apiKey: ${API_KEY} # Loaded from environment, must be 32+ chars
supportEmail: support@example.com # Must be valid email
email:
from: noreply@example.com
smtpHost: smtp.example.com
smtpPort: 587
allowInsecure: false
Real-time Configuration Updates
// DynamicService.cs - React to configuration changes
public class DynamicService
{
private readonly IOptionsMonitor<FeatureFlags> _features;
private readonly ILogger<DynamicService> _logger;
public DynamicService(
IOptionsMonitor<FeatureFlags> features,
ILogger<DynamicService> logger)
{
_features = features;
_logger = logger;
// Subscribe to configuration changes
features.OnChange(flags =>
{
_logger.LogInformation("Feature flags updated at {Time}", DateTime.UtcNow);
// Handle the configuration change
RefreshInternalState(flags);
});
}
// Always uses the latest configuration
public bool IsFeatureEnabled(string feature)
{
return _features.CurrentValue.IsEnabled(feature);
}
private void RefreshInternalState(FeatureFlags flags)
{
// Update any cached state based on new configuration
}
}
YAML Schema Support
Enable IntelliSense and Validation
# appsettings.yaml - Add schema reference
# yaml-language-server: $schema=./appsettings.schema.json
# Now you get IntelliSense and validation!
server:
url: https://api.example.com
timeout: 30
Generate schema from your configuration classes:
// Generate JSON Schema from your options classes
var schemaGenerator = new JsonSchemaGenerator();
var schema = schemaGenerator.Generate(typeof(AppConfiguration));
// Save to file for IDE support
File.WriteAllText("appsettings.schema.json", schema.ToJson());
Validate configuration at startup:
// Program.cs - Add schema validation
builder.Configuration.AddYamlFile("appsettings.yaml", optional: false)
.ValidateWithSchema("appsettings.schema.json");
Configuration Patterns
Multi-file Layering
// Program.cs - Layer configuration from multiple sources
builder.Configuration
// System-wide configuration
.AddYamlFile("/etc/myapp/config.yaml", optional: true)
// User-specific overrides
.AddYamlFile($"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}/.myapp/config.yaml", optional: true)
// Local development overrides
.AddYamlFile("config.local.yaml", optional: true)
// Environment variables take precedence
.AddEnvironmentVariables("MYAPP_");
Advanced Validation Patterns
// FluentValidationOptionsValidator.cs - Using FluentValidation
public class EmailOptionsValidator : AbstractValidator<EmailOptions>, IValidateOptions<EmailOptions>
{
public EmailOptionsValidator()
{
RuleFor(x => x.From).NotEmpty().EmailAddress();
RuleFor(x => x.SmtpHost).NotEmpty();
RuleFor(x => x.SmtpPort).InclusiveBetween(1, 65535);
// Complex conditional validation
When(x => x.SmtpPort == 25, () =>
{
RuleFor(x => x.AllowInsecure)
.Equal(true)
.WithMessage("Port 25 requires AllowInsecure=true");
});
When(x => x.SmtpHost.Contains("internal"), () =>
{
RuleFor(x => x.SmtpPort)
.Equal(25)
.WithMessage("Internal SMTP servers must use port 25");
});
}
public ValidateOptionsResult Validate(string name, EmailOptions options)
{
var result = Validate(options);
return result.IsValid
? ValidateOptionsResult.Success
: ValidateOptionsResult.Fail(result.Errors.Select(e => e.ErrorMessage));
}
}
// Program.cs - Register validators
services.AddSingleton<IValidateOptions<EmailOptions>, EmailOptionsValidator>();
services.Configure<EmailOptions>(Configuration.GetSection("email"))
.ValidateOnStart();
// Validation with dependencies
public class ApiKeyValidator : IValidateOptions<ApiSettings>
{
private readonly ISecretValidator _secretValidator;
public ApiKeyValidator(ISecretValidator secretValidator)
{
_secretValidator = secretValidator;
}
public async Task<ValidateOptionsResult> ValidateAsync(string name, ApiSettings options)
{
// Validate against external service
if (!await _secretValidator.IsValidApiKeyAsync(options.ApiKey))
{
return ValidateOptionsResult.Fail("Invalid API key");
}
return ValidateOptionsResult.Success;
}
}
Advanced Scenarios
Custom Type Converters
// TimeSpanConverter.cs - Support custom types in configuration
public class TimeSpanConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context,
CultureInfo culture, object value)
{
// Support formats like "30s", "5m", "1h"
if (value is string str)
{
if (str.EndsWith("s"))
return TimeSpan.FromSeconds(int.Parse(str[..^1]));
if (str.EndsWith("m"))
return TimeSpan.FromMinutes(int.Parse(str[..^1]));
if (str.EndsWith("h"))
return TimeSpan.FromHours(int.Parse(str[..^1]));
return TimeSpan.Parse(str);
}
return base.ConvertFrom(context, culture, value);
}
}
// Usage in configuration class
[TypeConverter(typeof(TimeSpanConverter))]
public TimeSpan CacheExpiration { get; set; }
Configuration Preprocessing
// Program.cs - Transform configuration before use
builder.Configuration.AddYamlFile("config.yaml", optional: false)
.Transform(config =>
{
// Replace environment variables
var processed = Environment.ExpandEnvironmentVariables(config);
// Custom placeholder resolution
processed = ResolvePlaceholders(processed);
// Decrypt sensitive values
processed = DecryptSecureValues(processed);
return processed;
});
Health Checks
// YamlConfigurationHealthCheck.cs - Monitor configuration health
public class YamlConfigurationHealthCheck : IHealthCheck
{
private readonly string _configPath;
public YamlConfigurationHealthCheck(string configPath)
{
_configPath = configPath;
}
public Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken cancellationToken = default)
{
try
{
// Verify file exists and is readable
if (!File.Exists(_configPath))
return Task.FromResult(HealthCheckResult.Unhealthy($"Configuration file not found: {_configPath}"));
// Try to parse the file
var yaml = File.ReadAllText(_configPath);
var parser = new VYamlParser();
parser.Parse(yaml);
return Task.FromResult(HealthCheckResult.Healthy("Configuration file is valid"));
}
catch (Exception ex)
{
return Task.FromResult(HealthCheckResult.Unhealthy($"Configuration error: {ex.Message}"));
}
}
}
// Program.cs - Register health check
services.AddHealthChecks()
.AddTypeActivatedCheck<YamlConfigurationHealthCheck>(
"config-yaml",
args: new[] { "appsettings.yaml" });
Troubleshooting
Common Issues
YAML parsing errors:
# INCORRECT - tabs not allowed for indentation
server:
host: localhost # This line uses a tab
# CORRECT - use spaces (2 or 4 spaces per level)
server:
host: localhost # This line uses 2 spaces
Type conversion failures:
// Program.cs - Enable detailed error messages
builder.Configuration.AddYamlFile("config.yaml", optional: false)
.EnableDetailedErrors();
// This will now show the exact path and value that failed
// Example: "Failed to convert 'server:timeout' value 'thirty' to type 'System.Int32'"
Validation errors:
// Clear validation error messages
try
{
var options = serviceProvider.GetRequiredService<IOptions<AppConfiguration>>();
var config = options.Value; // Validation happens here
}
catch (OptionsValidationException ex)
{
// Ex: "DataAnnotation validation failed for 'AppConfiguration' members:
// 'Database.ConnectionString' with the error: 'The ConnectionString field is required.'"
Console.WriteLine($"Configuration validation failed: {ex.Message}");
// Log all validation failures
foreach (var failure in ex.Failures)
{
Console.WriteLine($"- {failure}");
}
}
Missing configuration values:
// Safe configuration access patterns
// Option 1: Use GetValue with defaults
var timeout = Configuration.GetValue<int>("server:timeout", 30);
// Option 2: Check if section exists
if (Configuration.GetSection("features:newFeature").Exists())
{
// Feature configuration is present
var feature = Configuration.GetSection("features:newFeature").Get<FeatureConfig>();
}
// Option 3: Use IOptionsSnapshot for optional configuration
public class OptionalService
{
public OptionalService(IOptionsSnapshot<OptionalConfig> config)
{
// config.Value will have default values if section is missing
}
}
Migration Guide
From JSON Configuration
// Before - using JSON
builder.Configuration.AddJsonFile("appsettings.json");
// After - using YAML
builder.Configuration.AddYamlFile("appsettings.yaml");
Configuration structure remains identical—only the file format changes:
// appsettings.json
{
"server": {
"host": "localhost",
"port": 5000
},
"features": {
"enabled": ["search", "analytics"]
}
}
# appsettings.yaml - Same structure, more readable
server:
host: localhost
port: 5000
features:
enabled:
- search
- analytics
Gradual Migration
You can use both JSON and YAML together during migration:
// Program.cs - Use both providers during transition
builder.Configuration
// Keep existing JSON files
.AddJsonFile("appsettings.json", optional: false)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
// New YAML files override JSON settings
.AddYamlFile("appsettings.yaml", optional: true)
.AddYamlFile($"appsettings.{env.EnvironmentName}.yaml", optional: true);
// Migrate sections incrementally:
// 1. Move 'database' section to YAML first
// 2. Test thoroughly
// 3. Move next section
// 4. Eventually remove JSON files
Requirements
- .NET 8.0, .NET 9.0, or .NET Standard 2.0
- No additional runtime dependencies
Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
# Clone the repository
git clone https://github.com/mistial-dev/VYaml.Configuration.git
# Build the solution
dotnet build
# Run tests
dotnet test
# Run the sample application
dotnet run --project VYaml.Configuration.Sample
# Run benchmarks
sudo dotnet run -c Release --project benchmarks/VYaml.Configuration.Benchmarks
Refer to docs/benchmarks.md for updating the performance summary document.
Security
Found a security issue? Please email security@mistial.dev instead of using the issue tracker.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
Built on the excellent VYaml parser by Elringus. Special thanks to the .NET team for the extensible configuration framework.
Support
Ready to simplify your configuration? Install VYaml.Configuration and start using human-friendly YAML in your .NET applications today.
Product | Versions 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 is compatible. 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 is compatible. 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. |
-
.NETStandard 2.0
- Microsoft.Extensions.Configuration (>= 9.0.6)
- Microsoft.Extensions.Configuration.FileExtensions (>= 9.0.6)
- System.Buffers (>= 4.6.0)
- System.IO.Abstractions (>= 21.0.29)
- System.Memory (>= 4.6.0)
- System.Threading.Tasks.Extensions (>= 4.6.0)
- VYaml (>= 1.2.0)
-
net8.0
- Microsoft.Extensions.Configuration (>= 9.0.6)
- Microsoft.Extensions.Configuration.FileExtensions (>= 9.0.6)
- System.IO.Abstractions (>= 21.0.29)
- VYaml (>= 1.2.0)
-
net9.0
- Microsoft.Extensions.Configuration (>= 9.0.6)
- Microsoft.Extensions.Configuration.FileExtensions (>= 9.0.6)
- System.IO.Abstractions (>= 21.0.29)
- VYaml (>= 1.2.0)
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 |
---|---|---|
1.0.0 | 148 | 6/29/2025 |
Initial release of VYaml.Configuration with near-full YAML 1.2 support and Microsoft.Extensions.Configuration integration.