https://github.com/akikari/fox.configkit
Lightweight .NET configuration validation library with fail-fast startup checks and fluent API
https://github.com/akikari/fox.configkit
aspnetcore configuration configuration-validation csharp dotnet dotnet-library fluent-api microsoftextensionsoptions nuget-package option-pattern result-pattern secret-detection startup-validation validation
Last synced: 24 days ago
JSON representation
Lightweight .NET configuration validation library with fail-fast startup checks and fluent API
- Host: GitHub
- URL: https://github.com/akikari/fox.configkit
- Owner: akikari
- License: mit
- Created: 2026-02-13T13:09:03.000Z (2 months ago)
- Default Branch: main
- Last Pushed: 2026-03-25T09:27:20.000Z (about 1 month ago)
- Last Synced: 2026-03-26T12:51:31.055Z (about 1 month ago)
- Topics: aspnetcore, configuration, configuration-validation, csharp, dotnet, dotnet-library, fluent-api, microsoftextensionsoptions, nuget-package, option-pattern, result-pattern, secret-detection, startup-validation, validation
- Language: C#
- Homepage: https://github.com/akikari/ConfigKit
- Size: 152 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE.txt
- Codeowners: .github/CODEOWNERS
- Notice: NOTICE
Awesome Lists containing this project
README
# π― Fox.ConfigKit
[](https://dotnet.microsoft.com/)
[](https://github.com/akikari/Fox.ResultKit/actions/workflows/build-and-test.yml)
[](https://www.nuget.org/packages/Fox.ConfigKit/)
[](https://www.nuget.org/packages/Fox.ConfigKit/)
[](https://opensource.org/licenses/MIT)
[](https://codecov.io/gh/akikari/Fox.ConfigKit)
> **Lightweight .NET configuration validation library with fail-fast startup validation**
Fox.ConfigKit is a lightweight library for validating `IOptions` configurations at application startup. Catch configuration errors before they cause runtime failures with fluent, expressive validation rules.
## π Table of Contents
- [Why Fox.ConfigKit?](#why-foxconfigkit)
- [Features](#features)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Validation Rules](#validation-rules)
- [Advanced Scenarios](#advanced-scenarios)
- [Sample Application](#sample-application)
- [Design Principles](#design-principles)
- [Requirements](#requirements)
- [Real-World Example](#real-world-example)
- [Contributing](#contributing)
- [License](#license)
- [Author](#author)
- [Project Status](#project-status)
- [Related Projects](#related-projects)
- [Support](#support)
## π€ Why Fox.ConfigKit?
**Traditional approach:**
```csharp
// β Configuration errors discovered at runtime
public class MyService
{
private readonly MyConfig config;
public void DoWork()
{
// Crashes here if config.ApiUrl is null or invalid!
var client = new HttpClient { BaseAddress = new Uri(config.ApiUrl) };
}
}
```
**Fox.ConfigKit approach:**
```csharp
// β
Configuration errors caught at startup
builder.Services.AddConfigKit("MyConfig")
.NotEmpty(c => c.ApiUrl, "API URL is required")
.UrlReachable(c => c.ApiUrl, message: "API is not reachable")
.ValidateOnStartup();
// Application won't start if configuration is invalid!
```
## β¨ Features
- β
**Fail-Fast Validation** - Catch configuration errors at application startup
- β
**Fluent API** - Intuitive, type-safe configuration validation
- β
**Generic Type Support** - Validate any `IComparable` type (int, decimal, DateTime, TimeSpan, etc.)
- β
**Conditional Validation** - Apply rules based on environment or other properties
- β
**File System Validation** - Verify directories and files exist
- β
**Network Validation** - Check URL reachability at startup
- β
**Security Validation** - Detect plain-text secrets in configuration
- β
**IOptions Integration** - Seamless integration with `Microsoft.Extensions.Options`
- β
**No Third-Party Dependencies** - Only uses core Microsoft.Extensions packages
- β
**Multi-Targeting** - Supports .NET 8.0, .NET 9.0, and .NET 10.0
## π¦ Installation
```bash
dotnet add package Fox.ConfigKit
```
**NuGet Package Manager:**
```
Install-Package Fox.ConfigKit
```
**PackageReference:**
```xml
```
## π Quick Start
### 1. Define Your Configuration Class
```csharp
public sealed class DatabaseConfig
{
public string ConnectionString { get; set; } = string.Empty;
public int MaxPoolSize { get; set; }
public int CommandTimeoutSeconds { get; set; }
}
```
### 2. Configure appsettings.json
```json
{
"Database": {
"ConnectionString": "Server=localhost;Database=MyDb;User Id=sa;Password=YourPassword123;",
"MaxPoolSize": 100,
"CommandTimeoutSeconds": 30
},
"Api": {
"BaseUrl": "https://api.example.com",
"ApiKey": "your-api-key-here",
"TimeoutSeconds": 30,
"MaxRetries": 3
},
"Logging": {
"LogDirectory": "C:\\Logs\\MyApp",
"MinimumLevel": "Information",
"RetentionDays": 30
}
}
```
### 3. Register and Validate in Program.cs
```csharp
using Fox.ConfigKit;
using Fox.ConfigKit.Validation;
var builder = WebApplication.CreateBuilder(args);
// Register configuration with validation
builder.Services.AddConfigKit("Database")
.NotEmpty(c => c.ConnectionString, "Connection string is required")
.InRange(c => c.MaxPoolSize, 1, 1000, "Max pool size must be between 1 and 1000")
.InRange(c => c.CommandTimeoutSeconds, 1, 600, "Command timeout must be between 1 and 600 seconds")
.ValidateOnStartup();
var app = builder.Build();
app.Run();
```
### 4. Inject and Use
```csharp
public class MyService
{
private readonly DatabaseConfig config;
public MyService(IOptions config)
{
this.config = config.Value; // Already validated at startup!
}
}
```
## π Validation Rules
### String Validation
| Method | Description |
|--------|-------------|
| `NotEmpty(selector, message)` | Ensures string is not null or empty |
| `NotNull(selector, message)` | Ensures value is not null |
| `MatchesPattern(selector, regex, message)` | Validates string against regex pattern |
**Example:**
```csharp
builder.Services.AddConfigKit("App")
.NotEmpty(c => c.Name, "Application name is required")
.MatchesPattern(c => c.Version, @"^\d+\.\d+\.\d+$", "Version must be X.Y.Z format")
.ValidateOnStartup();
```
### Comparable Value Validation
All comparison validation methods support any `IComparable` type including `int`, `decimal`, `DateTime`, `TimeSpan`, and more.
| Method | Description | Boundary |
|--------|-------------|----------|
| `GreaterThan(selector, min, message)` | Ensures value is greater than minimum | Exclusive (>) |
| `LessThan(selector, max, message)` | Ensures value is less than maximum | Exclusive (<) |
| `Minimum(selector, min, message)` | Ensures value is at least minimum | Inclusive (>=) |
| `Maximum(selector, max, message)` | Ensures value is at most maximum | Inclusive (<=) |
| `InRange(selector, min, max, message)` | Ensures value is within range | Inclusive (>=, <=) |
**Example with integers:**
```csharp
builder.Services.AddConfigKit("Api")
.GreaterThan(c => c.Port, 1024, "Port must be > 1024")
.Maximum(c => c.Port, 65535, "Port must be <= 65535")
.InRange(c => c.MaxRetries, 0, 10, "Max retries must be between 0 and 10")
.ValidateOnStartup();
```
**Example with decimals:**
```csharp
builder.Services.AddConfigKit("Product")
.Minimum(c => c.Price, 0.01m, "Price must be at least $0.01")
.Maximum(c => c.Discount, 0.5m, "Discount cannot exceed 50%")
.ValidateOnStartup();
```
**Example with DateTime:**
```csharp
builder.Services.AddConfigKit("Campaign")
.Minimum(c => c.StartDate, DateTime.Today, "Campaign must start today or later")
.LessThan(c => c.EndDate, new DateTime(2025, 12, 31), "Campaign must end before 2025")
.ValidateOnStartup();
```
**Example with TimeSpan:**
```csharp
builder.Services.AddConfigKit("Api")
.GreaterThan(c => c.Timeout, TimeSpan.Zero, "Timeout must be positive")
.Maximum(c => c.Timeout, TimeSpan.FromMinutes(5), "Timeout cannot exceed 5 minutes")
.ValidateOnStartup();
```
### Property-to-Property Comparison
Compare two properties within the same configuration object. Useful for validating date ranges, min/max pairs, and batch processing configurations.
| Method | Description | Boundary |
|--------|-------------|----------|
| `GreaterThanProperty(selector, compareToSelector, message)` | Ensures property is greater than another property | Exclusive (>) |
| `LessThanProperty(selector, compareToSelector, message)` | Ensures property is less than another property | Exclusive (<) |
| `MinimumProperty(selector, compareToSelector, message)` | Ensures property is at least another property | Inclusive (>=) |
| `MaximumProperty(selector, compareToSelector, message)` | Ensures property is at most another property | Inclusive (<=) |
**Example with date ranges:**
```csharp
builder.Services.AddConfigKit("Campaign")
.GreaterThanProperty(c => c.EndDate, c => c.StartDate, "End date must be after start date")
.ValidateOnStartup();
```
**Example with batch processing:**
```csharp
builder.Services.AddConfigKit("Migration")
.MinimumProperty(c => c.RecordsPerRun, c => c.BatchSize, "RecordsPerRun must be >= BatchSize")
.ValidateOnStartup();
```
**Example with price ranges:**
```csharp
builder.Services.AddConfigKit("Product")
.LessThanProperty(c => c.MinPrice, c => c.MaxPrice, "MinPrice must be less than MaxPrice")
.ValidateOnStartup();
```
### File System Validation
| Method | Description |
|--------|-------------|
| `FileExists(selector, message)` | Validates file exists at path |
| `DirectoryExists(selector, message)` | Validates directory exists at path |
**Example:**
```csharp
builder.Services.AddConfigKit("Logging")
.NotEmpty(c => c.LogDirectory, "Log directory is required")
.DirectoryExists(c => c.LogDirectory, message: "Log directory does not exist")
.ValidateOnStartup();
```
### Network Validation
| Method | Description |
|--------|-------------|
| `UrlReachable(selector, timeout, message)` | Validates URL is reachable via HTTP HEAD request |
**Example:**
```csharp
builder.Services.AddConfigKit("ExternalApi")
.NotEmpty(c => c.BaseUrl, "API URL is required")
.UrlReachable(c => c.BaseUrl, timeout: TimeSpan.FromSeconds(10), message: "API is not reachable")
.ValidateOnStartup();
```
### Security Validation
| Method | Description |
|--------|-------------|
| `NoPlainTextSecrets(selector, message)` | Detects plain-text secrets using pattern matching |
**Example:**
```csharp
builder.Services.AddConfigKit("Api")
.NotEmpty(c => c.ApiKey, "API key is required")
.NoPlainTextSecrets(c => c.ApiKey, "API key appears to be a plain-text secret")
.ValidateOnStartup();
```
**Detected secret patterns:**
- OpenAI API keys (`sk-...`)
- Google API keys (`AIza...`)
- AWS Access Keys (`AKIA...`)
- Bearer tokens
- Generic Base64 secrets
- Hexadecimal secrets (64 chars)
### Environment Validation
| Method | Description |
|--------|-------------|
| `EnvironmentVariableExists(selector, message)` | Validates environment variable exists |
**Example:**
```csharp
builder.Services.AddConfigKit("App")
.NotEmpty(c => c.EnvironmentName, "Environment name is required")
.EnvironmentVariableExists(c => c.RequiredEnvVar, "Required environment variable not set")
.ValidateOnStartup();
```
## π₯ Advanced Scenarios
### Conditional Validation
Apply validation rules conditionally based on configuration values:
```csharp
builder.Services.AddConfigKit("Security")
.NotEmpty(c => c.Environment, "Environment is required")
.When(c => c.Environment == "Production", b =>
{
// These rules only apply in production
b.NotEmpty(c => c.CertificatePath, "Certificate is required in production")
.FileExists(c => c.CertificatePath, message: "Certificate file not found");
})
.When(c => c.RequireHttps, b =>
{
// These rules only apply when HTTPS is required
b.FileExists(c => c.CertificatePath, message: "HTTPS requires certificate");
})
.ValidateOnStartup();
```
### Cross-Property Validation
```csharp
public sealed class DatabaseConfig
{
public string ConnectionString { get; set; } = string.Empty;
public bool RequireSsl { get; set; }
}
builder.Services.AddConfigKit("Database")
.NotEmpty(c => c.ConnectionString, "Connection string is required")
.When(c => c.RequireSsl, b =>
{
b.MatchesPattern(c => c.ConnectionString, "Encrypt=True|Encrypt=true",
"SSL required but connection string does not specify Encrypt=True");
})
.ValidateOnStartup();
```
### Environment-Specific Configuration Structures
When different environments require structurally different configurations (e.g., local authentication in DEV, OAuth in PROD/TEST), you have two approaches:
#### Approach 1: Union Configuration with Conditional Validation
Use a single configuration class with nullable properties for environment-specific fields:
```csharp
public sealed class AuthConfig
{
public string Type { get; set; } = string.Empty; // "Local" or "OAuth"
// DEV environment only
public string? LocalUsername { get; set; }
public string? LocalPassword { get; set; }
// PROD/TEST environment only
public string? OAuthClientId { get; set; }
public string? OAuthClientSecret { get; set; }
public string? OAuthAuthority { get; set; }
}
builder.Services.AddConfigKit("Auth")
.NotEmpty(c => c.Type, "Authentication type is required")
.When(c => c.Type == "Local", b =>
{
b.NotEmpty(c => c.LocalUsername, "Username required for local auth")
.NotEmpty(c => c.LocalPassword, "Password required for local auth");
})
.When(c => c.Type == "OAuth", b =>
{
b.NotEmpty(c => c.OAuthClientId, "ClientId required for OAuth")
.NotEmpty(c => c.OAuthClientSecret, "ClientSecret required for OAuth")
.NotEmpty(c => c.OAuthAuthority, "Authority URL required for OAuth")
.UrlReachable(c => c.OAuthAuthority!, TimeSpan.FromSeconds(10),
"OAuth authority not reachable");
})
.ValidateOnStartup();
```
**Pros:**
- β
Single configuration class
- β
`appsettings.{Environment}.json` automatically overrides values
- β
Works with existing `When()` API
**Cons:**
- β Nullable properties for environment-specific fields
- β Less type-safe (union type instead of separate types)
#### Approach 2: Environment-Specific Configuration Classes
Use separate configuration classes for each environment and register conditionally:
```csharp
public interface IAuthConfig
{
string Type { get; }
}
public sealed class LocalAuthConfig : IAuthConfig
{
public string Type => "Local";
public string Username { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
}
public sealed class OAuthConfig : IAuthConfig
{
public string Type => "OAuth";
public string ClientId { get; set; } = string.Empty;
public string ClientSecret { get; set; } = string.Empty;
public string Authority { get; set; } = string.Empty;
}
// Program.cs - conditional registration based on environment
if (builder.Environment.IsDevelopment())
{
builder.Services.AddConfigKit("Auth")
.NotEmpty(c => c.Username, "Username required")
.NotEmpty(c => c.Password, "Password required")
.ValidateOnStartup();
builder.Services.AddSingleton(sp =>
sp.GetRequiredService>().Value);
}
else // Production/Test
{
builder.Services.AddConfigKit("Auth")
.NotEmpty(c => c.ClientId, "ClientId required")
.NotEmpty(c => c.ClientSecret, "ClientSecret required")
.NotEmpty(c => c.Authority, "Authority URL required")
.UrlReachable(c => c.Authority, TimeSpan.FromSeconds(10),
"OAuth authority not reachable")
.ValidateOnStartup();
builder.Services.AddSingleton(sp =>
sp.GetRequiredService>().Value);
}
```
**Pros:**
- β
Type-safe configuration classes without nullable properties
- β
Clear separation of environment-specific concerns
- β
Compile-time enforcement of configuration structure
**Cons:**
- β More complex DI registration (if/else in startup)
- β Requires separate `appsettings.{Environment}.json` files with different schemas
- β Two separate validation builders
**Recommendation:** Use **Approach 1** for simple environment differences (different values). Use **Approach 2** when environments have fundamentally different authentication mechanisms or infrastructure dependencies.
### Custom Validation Rules
Create custom validation rules by inheriting from `ValidationRuleBase`:
```csharp
using Fox.ConfigKit.Validation;
internal sealed class CustomRule : ValidationRuleBase, IValidationRule where T : class
{
private readonly Func getValue;
private readonly string propertyName;
private readonly string? message;
public CustomRule(Expression> selector, string? message = null)
{
this.getValue = selector.Compile();
this.propertyName = GetPropertyName(selector);
this.message = message;
}
public ConfigValidationError? Validate(T options, string sectionName)
{
var value = getValue(options);
if (string.IsNullOrEmpty(value))
{
var key = $"{sectionName}:{propertyName}";
var errorMessage = message ?? $"{propertyName} is invalid";
return new ConfigValidationError(key, errorMessage, value, ["Provide a valid value"]);
}
return null;
}
}
// Extension method
public static class CustomValidationExtensions
{
public static ConfigValidationBuilder MyCustomValidation(
this ConfigValidationBuilder builder,
Expression> selector,
string? message = null) where T : class
{
return builder.AddRule(new CustomRule(selector, message));
}
}
```
## π Result Pattern Integration (Optional)
For applications using [Fox.ResultKit](https://github.com/akikari/Fox.ResultKit), the **Fox.ConfigKit.ResultKit** integration package enables functional-style configuration validation with Railway Oriented Programming.
### Installation
```bash
dotnet add package Fox.ConfigKit.ResultKit
```
### Functional Validation (Alternative to ValidateOnStartup)
Instead of exception-based validation at startup, use `Result` for explicit error handling:
```csharp
using Fox.ConfigKit.ResultKit;
using Fox.ResultKit;
var builder = WebApplication.CreateBuilder(args);
// Register configuration WITHOUT ValidateOnStartup()
builder.Services.AddConfigKit("Application")
.NotEmpty(c => c.Name, "Application name is required")
.Minimum(c => c.MaxConcurrentRequests, 1)
.Maximum(c => c.MaxConcurrentRequests, 1000);
// β No .ValidateOnStartup() call!
builder.Services.AddConfigKit("Database")
.NotEmpty(c => c.ConnectionString);
var app = builder.Build();
// Explicit validation with Result pattern
var appConfig = app.Services.GetRequiredService>().Value;
var dbConfig = app.Services.GetRequiredService>().Value;
// Composable validation pipeline
var startupResult = ConfigValidator.Validate()
.NotEmpty(c => c.Name, "Application name is required")
.Minimum(c => c.MaxConcurrentRequests, 1)
.ToResult(appConfig)
.Bind(_ => ConfigValidator.Validate()
.NotEmpty(c => c.ConnectionString, "Connection string required")
.ToResult(dbConfig));
// Functional error handling
startupResult.Match(
onSuccess: _ =>
{
app.Logger.LogInformation("All configurations valid");
app.Run();
},
onFailure: error =>
{
app.Logger.LogCritical("Configuration validation failed: {Error}", error.Message);
Environment.Exit(1);
}
);
```
### Collecting All Validation Errors
Use `ToErrorsResult()` to collect **all** validation errors instead of stopping at the first one:
```csharp
var validationResult = ConfigValidator.Validate()
.NotEmpty(c => c.Name, "Name is required")
.InRange(c => c.MaxConcurrentRequests, 1, 1000)
.NotEmpty(c => c.Version, "Version is required")
.ToErrorsResult(appConfig);
if (validationResult.IsFailure)
{
app.Logger.LogCritical("Configuration has {Count} errors:", validationResult.Errors.Count);
foreach (var error in validationResult.Errors)
{
app.Logger.LogError(" - {ErrorMessage}", error.Message);
}
Environment.Exit(1);
}
app.Run();
```
### When to Use Result Pattern vs ValidateOnStartup
| Scenario | Use `ValidateOnStartup()` | Use `ToResult()` / Result Pattern |
|----------|--------------------------|----------------------------------|
| **Simple ASP.NET Core app** | β
Recommended (fail-fast) | β Overkill |
| **Console/Worker apps** | β No DI startup | β
Recommended |
| **Complex startup logic** | π‘ Limited control | β
Full control over errors |
| **Multiple configs to validate** | π‘ Sequential exceptions | β
Composable chain with `Bind()` |
| **Need all errors at once** | β Stops at first error | β
`ToErrorsResult()` collects all |
| **Unit testing validation** | π‘ Exception-based asserts | β
Result-based asserts |
| **Graceful shutdown on error** | β Exception crash | β
`Environment.Exit(1)` |
| **Already using Railway pattern** | π‘ Inconsistent style | β
Consistent functional style |
### Standalone Validation (Without DI)
For console apps, scripts, or unit tests where DI is not available:
```csharp
using Fox.ConfigKit.ResultKit;
// Load configuration from file/environment
var config = LoadConfigurationFromFile("appsettings.json");
// Validate without dependency injection
var result = ConfigValidator.Validate()
.NotEmpty(c => c.Name, "Name is required")
.InRange(c => c.Port, 1, 65535, "Invalid port")
.ToResult(config);
return result.Match(
onSuccess: validConfig => RunApplication(validConfig),
onFailure: error =>
{
Console.WriteLine($"Configuration error: {error}");
return 1; // Exit code
}
);
```
**Learn more:** See the [Fox.ConfigKit.ResultKit README](https://github.com/akikari/Fox.ConfigKit/tree/main/src/Fox.ConfigKit.ResultKit) for detailed examples and advanced patterns.
## π Sample Application
A comprehensive sample WebApi application is available in the repository demonstrating:
- β
Application-wide configuration validation
- β
Database connection string validation
- β
External API configuration with URL reachability checks
- β
File system validation for log directories
- β
Environment-based conditional validation
- β
Security configuration with certificate validation
**Run the sample:**
```bash
cd samples/Fox.ConfigKit.Samples.WebApi
dotnet run
```
**Explore:**
- Open `https://localhost:5001/swagger`
- View validated configurations via `/api/configuration/*` endpoints
- See [sample README](samples/Fox.ConfigKit.Samples.WebApi/README.md) for details
## π― Design Principles
1. **Fail-Fast** - Catch configuration errors at startup, not at runtime
2. **Explicit Validation** - Make validation rules clear and discoverable
3. **Type-Safe** - Leverage C# type system for compile-time safety
4. **Fluent API** - Intuitive, chainable validation rules
5. **No Third-Party Dependencies** - Only core Microsoft.Extensions packages, no external libraries
6. **Developer-Friendly** - Clear error messages, excellent IntelliSense
## π§ Requirements
- .NET 8.0 or higher
- C# 12 or higher (for modern language features)
- Nullable reference types enabled (recommended)
## π― Real-World Example
See this package in action within a complete production-grade application: **[Fox.TaskFlow](https://github.com/akikari/Fox.TaskFlow)** - A comprehensive demonstration showcasing real-world integration of seven Fox.*Kit packages in a task management system built with Clean Architecture, SOLID principles, and modern .NET 10 practices.
## π€ Contributing
**Fox.ConfigKit is intentionally lightweight and feature-focused.** The goal is to remain a simple library with minimal dependencies for configuration validation.
### What We Welcome
- β
**Bug fixes** - Issues with existing functionality
- β
**Documentation improvements** - Clarifications, examples, typo fixes
- β
**Performance optimizations** - Without breaking API compatibility
- β
**New validation rules** - Following existing patterns
### What We Generally Do Not Accept
- β New dependencies or third-party packages
- β Large feature additions that increase complexity
- β Breaking API changes
If you want to propose a significant change, please open an issue first to discuss whether it aligns with the project's philosophy.
### Build Policy
The project enforces a **strict build policy** to ensure code quality:
- β **No errors allowed** - Build must be error-free
- β **No warnings allowed** - All compiler warnings must be resolved
- β **No messages allowed** - Informational messages must be suppressed or addressed
All pull requests must pass this requirement.
### Code Quality Standards
Fox.ValidationKit follows strict coding standards:
- **Comprehensive unit tests required** (xUnit + FluentAssertions)
- **Maximum test coverage required** - Aim for 100% line and branch coverage. Tests may only be omitted if they would introduce artificial complexity (e.g., testing unreachable code paths, framework internals, or compiler-generated code). Use `[ExcludeFromCodeCoverage]` sparingly and only for justified cases.
- **XML documentation for all public APIs** - Clear, concise documentation with examples
- **Follow Microsoft coding conventions** - See `.github/copilot-instructions.md` for project-specific style
- **Zero warnings, zero errors build policy** - Strict enforcement
### Code Style
- Follow the existing code style (see `.github/copilot-instructions.md`)
- Use file-scoped namespaces
- Enable nullable reference types
- Add XML documentation for public APIs
- Write unit tests for new features
- Use expression-bodied members for simple properties
- Auto-properties preferred over backing fields
### How to Contribute
1. Fork the repository
2. Create a feature branch from `main`
3. Follow the coding standards in `.github/copilot-instructions.md`
4. Ensure all tests pass (`dotnet test`)
5. Submit a pull request
## π License
This project is licensed under the MIT License - see the [LICENSE.txt](LICENSE.txt) file for details.
## π€ Author
**KΓ‘roly AkΓ‘cz**
- GitHub: [@akikari](https://github.com/akikari)
- Repository: [Fox.ConfigKit](https://github.com/akikari/Fox.ConfigKit)
## π Project Status
[](https://www.nuget.org/packages/Fox.ConfigKit/)
See [CHANGELOG.md](CHANGELOG.md) for version history.
## π Related Projects
- [Fox.ResultKit](https://github.com/akikari/Fox.ResultKit) - Lightweight Result pattern library for Railway Oriented Programming
- [Fox.ConfigKit.ResultKit](https://www.nuget.org/packages/Fox.ConfigKit.ResultKit) - Integration package for using ConfigKit with Result pattern
## π Support
For issues, questions, or feature requests, please open an issue in the [GitHub repository](https://github.com/akikari/Fox.ConfigKit/issues).