Lyo.Configuration.Validation 2.0.0

dotnet add package Lyo.Configuration.Validation --version 2.0.0
                    
NuGet\Install-Package Lyo.Configuration.Validation -Version 2.0.0
                    
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="Lyo.Configuration.Validation" Version="2.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Lyo.Configuration.Validation" Version="2.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Lyo.Configuration.Validation" />
                    
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 Lyo.Configuration.Validation --version 2.0.0
                    
#r "nuget: Lyo.Configuration.Validation, 2.0.0"
                    
#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 Lyo.Configuration.Validation@2.0.0
                    
#: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=Lyo.Configuration.Validation&version=2.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Lyo.Configuration.Validation&version=2.0.0
                    
Install as a Cake Tool

Lyo.Configuration.Validation

Takes the same ValidationSchema documents the rest of the suite uses — a named WhereClause tree, typically published by an API — and applies them to a host's configuration.

Two entry points cover the two useful shapes. ValidateSectionAsync<TOptions> binds a section with LyoOptions.Bind and validates the bound instance, so the query engine evaluates rules against real CLR properties. ValidateKeysAsync skips binding and resolves each rule's field path as a configuration key, which is what you want for keys no options type owns, or for checking configuration before any options type exists.

Comparison semantics are never reimplemented here. ConfigurationClauseEvaluator walks the clause tree and reads keys, then hands each leaf to the where-clause engine wrapped in a ConfigurationProbe<TValue>, so operators behave exactly as they do for entities.

Features

  • Raw-key rules. Dotted rule paths become configuration keys in ConfigurationClauseEvaluator (Database.PortDatabase:Port).
  • Bound-options rules. ValidateSectionAsync<TOptions> binds the section first, then validates the POCO.
  • Operators unchanged. Leaf comparisons go to IWhereClauseService, so Regex, In, Contains, and numeric compares match query behaviour.
  • Collection size. A trailing Count segment reads the child count of the section it names, so Hosts.Count works over an array section.
  • Self-contained registration. AddConfigurationValidation TryAdds the lightweight evaluator, so no full query stack is required.

Examples

Check configuration keys against an API-published schema

using Lyo.Configuration.Validation;

services.AddConfigurationValidationFromConfiguration(configuration);

// Seed rules however the host gets them (API client, Postgres store, literal).
await store.SaveAsync(new ValidationSchema {
    Key = "host.startup.v1",
    Constraints = new GroupClause(GroupOperatorEnum.And, [
        new ConditionClause("Database.Port", ComparisonOperatorEnum.GreaterThan, 0),
        new ConditionClause("Database.Host", ComparisonOperatorEnum.NotEquals, ""),
    ]),
}, ct);

var result = await validator.ValidateKeysAsync("host.startup.v1", ct: ct);
if (result.IsFailure)
    throw new InvalidOperationException(string.Join("; ", result.Errors.Select(e => e.Message)));

Check a bound options type

var result = await validator.ValidateSectionAsync<DatabaseOptions>("database.v1", DatabaseOptions.SectionName, ct);
DatabaseOptions options = result.ValueOrThrow();

Options

{
  "ConfigurationValidation": {
    "TreatDotAsKeyDelimiter": true,
    "FailWhenSchemaMissing": true,
    "DefaultSectionName": null
  }
}

Package contents

  • ConfigurationValidator / IConfigurationValidatorValidateKeysAsync and ValidateSectionAsync<TOptions>.
  • ConfigurationClauseEvaluator — an IValidationClauseEvaluator that reads configuration keys and passes non-configuration targets straight through to the inner evaluator.
  • ConfigurationProbe<TValue> — the single-property carrier used to hand one parsed configuration value to the where-clause engine.
  • ConfigurationValidationOptions — missing-schema behaviour, key delimiter handling, and the default section.
  • Extensions.AddConfigurationValidation — the three house registration overloads.

How a rule reaches a configuration value

There is nothing for the query engine to reflect over, because configuration is a flat string store. The evaluator therefore owns two things and delegates the rest.

Key lookup is one: a rule field of Database.Port becomes Database:Port (unless TreatDotAsKeyDelimiter is off), and a trailing Count segment falls back to the child count of the named section. The tree walk is the other, building the WhereClauseExplainNode tree that WhereClauseExplainAnalysis then turns into a blocking path, a failure summary, and per-branch outcomes for failed Or groups.

Comparison is not owned here. Each leaf is parsed into the shape implied by the rule's own filter literal — an integer literal yields ConfigurationProbe<long?>, a JSON string yields ConfigurationProbe<string>, and so on — and the condition is re-asked of the inner evaluator with its field rewritten to Value. A value that will not parse is left null, which fails positive operators and satisfies negative ones, the same shape as a missing key.

Registration

The schema store and compiler (AddValidation), the lightweight WhereClauseEvaluator and its ValueConversionService, and a ConfigurationClauseEvaluator wrapping WhereClauseServiceEvaluator as the host's IValidationClauseEvaluator are what AddConfigurationValidation registers.

Every registration is a TryAdd, so a host that already called AddLyoQueryServices() keeps its cached, metered where-clause service and this package layers on top of it. Because the evaluator passes non-IConfiguration targets through, that single registration also serves ordinary object validation.

Dependencies

Generated from ProjectReference / PackageReference (same model as docs/Lyo.ProjectGraph.html).

  • Lyo.Common.Core (direct, lyo)
  • Lyo.Configuration (direct, lyo)
  • Lyo.Exceptions (direct, lyo)
  • Lyo.Query.Evaluation (direct, lyo)
  • Lyo.Validation (direct, lyo)
  • Microsoft.Extensions.DependencyInjection.Abstractions 10.0.5 (direct, microsoft)
  • Microsoft.Extensions.Options 10.0.5 (direct, microsoft)
  • System.Text.Json 10.0.5 (direct, microsoft, netstandard2.0)
  • Lyo.Common.Json (transitive, lyo)
  • Lyo.Common.Metadata (transitive, lyo)
  • Lyo.Metrics (transitive, lyo)
  • Lyo.Parameters (transitive, lyo)
  • Lyo.Query.Models (transitive, lyo)
  • Lyo.Result (transitive, lyo)
  • Lyo.Validation.Models (transitive, lyo)
  • Microsoft.Bcl.AsyncInterfaces 10.0.5 (transitive, microsoft, netstandard2.0)
  • Microsoft.Extensions.Configuration.Binder 10.0.5 (transitive, microsoft)
  • System.ComponentModel.Annotations 5.0.0 (transitive, microsoft)
  • System.Memory 4.6.3 (transitive, microsoft, netstandard2.0)
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 is compatible.  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
2.0.0 44 9/9/2026