CoreEx.Validation
4.0.0-preview-1
dotnet add package CoreEx.Validation --version 4.0.0-preview-1
NuGet\Install-Package CoreEx.Validation -Version 4.0.0-preview-1
<PackageReference Include="CoreEx.Validation" Version="4.0.0-preview-1" />
<PackageVersion Include="CoreEx.Validation" Version="4.0.0-preview-1" />
<PackageReference Include="CoreEx.Validation" />
paket add CoreEx.Validation --version 4.0.0-preview-1
#r "nuget: CoreEx.Validation, 4.0.0-preview-1"
#:package CoreEx.Validation@4.0.0-preview-1
#addin nuget:?package=CoreEx.Validation&version=4.0.0-preview-1&prerelease
#tool nuget:?package=CoreEx.Validation&version=4.0.0-preview-1&prerelease
CoreEx.Validation
Provides a fluent, property-centric validation framework for .NET classes: composable rules, conditional clauses, strongly-typed error messages, and deep integration with the CoreEx execution and exception model.
Overview
CoreEx.Validation fills the gap between primitive data-annotation validation and a fully featured domain validation library. The framework is built around the concept of a Validator<TEntity> that owns a set of PropertyRule chains — one chain per property. Each chain is declared fluently using HasProperty/HasRuleFor, and individual rules are appended to the chain with extension methods defined in ValidationExtensions.
Every rule invoked on a property chain runs asynchronously and receives a PropertyContext<TEntity, TProperty> that carries the current entity, the resolved property value, the accumulated error list, and a reference to the owning ValidationContext<TEntity>. When a rule adds an error it does so through the context, which means all rules in the chain continue executing and all errors for all properties are collected before the framework decides to throw or return.
Validation is initiated by calling ValidateAsync on a validator instance and inspecting the returned IValidationContext<TEntity>, or by calling ValidateAndThrowAsync which converts errors to a CoreEx ValidationException automatically.
Motivation
- The standard .NET
DataAnnotationsmodel is attribute-only, non-composable, and cannot express cross-property rules or async checks cleanly. - FluentValidation is a popular alternative but requires a separate NuGet dependency and has a different abstraction model; CoreEx.Validation integrates tightly with
ExecutionContext,LTextlocalisation,IValidatorEx, and the CoreEx exception hierarchy. - Property rules and clauses are plain sealed classes; extension methods in
ValidationExtensionsare the only public API surface, making it trivial to discover and extend the rule set. - Common validators (
CommonValidator<TValue>) allow validation logic to be extracted from a specific entity and reused across validators without duplication. RuleSet<TEntity>groups multiple rules under a shared predicate, enabling scenario-specific validation blocks that only activate under defined conditions.
Key capabilities
- ✅ Fluent property-rule chains: properties are declared with
HasProperty/HasRuleForand rules are appended via extension methods; the chain executes every rule in order, collecting all errors before reporting. - 📋 Rich built-in rule set: mandatory, string (length, regex), numeric, decimal/floating-point precision, between/range, comparison (value, property, values), enum, email, wildcard, null/none/empty, error, collection, dictionary, entity, common, reference data, and interop rules cover the vast majority of domain validation needs.
- 🧩 Conditional clauses:
When/WhenValue/WhenHasValueandDependsOnclauses short-circuit a rule when a condition is not met, enabling context-sensitive rules without branching in the rule body. - ⚡ Fully async: every rule and clause is
async-capable;PredicateAsync<TEntity, TProperty>delegates allow awaiting external services within a clause. - 🔧 Common and inline validators:
CommonValidator<TValue>encapsulates reusable validation logic;InlineValidator<TValue>is the compositional base used by bothCommonValidatorandCommonRule. - 📝 Localised error messages: every rule accepts an optional
LTextoverride; default messages are defined inValidatorStringsand resolved through CoreEx localisation. - 🔍 Context-aware property paths:
PropertyContexttracks fully qualified property names (both .NET and JSON) so error messages map precisely to the correct field in API responses. - 💬 RuleSet grouping:
RuleSet<TEntity>collects a block of rules that only execute when aPredicate<ValidationContext<TEntity>>returnstrue. - 🧩 Base-validator include:
Validator<TEntity>/AbstractValidator<TEntity>and the fluentIncludemethod allow a base validator to be composed into a derived validator. - Interop bridge:
InteropRuleand the.Interop()extension forward validation to anyIValidator/IValidator<T>(e.g. a FluentValidation validator) and merge errors into the CoreEx context.
Key types
| Type | Description |
|---|---|
Validator |
Static factory and service-locator entry point: Create<TEntity>(), Get<TValidator>(), and CreateCommon<TValue>(). |
Validator<TEntity> |
Concrete entity validator; owns rule chains declared fluently via HasProperty/HasRuleFor; exposes ValidateAsync and ValidateAndThrowAsync. |
AbstractValidator<TEntity> |
Convenience base class for defining reusable named validators without generic constraints; derives from Validator<TEntity>. |
AbstractValidator<TEntity, TParent> |
Convenience base class for validators with a parent-entity context; enables cross-entity validation. |
CommonValidator<TValue> |
Reusable value-level validator; wraps an InlineValidator<TValue>; used with the Common/.Common() rule extension to apply shared logic across properties. |
ValidationContext<TEntity> |
The live context for a single validation execution; accumulates ValidationMessageItem errors across all property chains; implements IValidationContext<TEntity>. |
ValidationArgs |
Immutable options for a validation run: UseJsonNames, FullyQualifiedEntityName, FullyQualifiedJsonEntityName, ServiceProvider and Parameters. |
PropertyContext<TEntity, TProperty> |
Per-rule execution context; carries entity, value, property metadata, and the owning ValidationContext; passed to every rule and clause. |
CompareOperator |
Enum: Equal, NotEqual, LessThan, LessThanOrEqualTo, GreaterThan, GreaterThanOrEqualTo; used by the compare rules. |
ValidationExtensions |
Static partial class aggregating all rule and clause extension methods into a single discoverable surface. |
Clauses
Clauses are conditional guards that run before the rule body. When a clause returns false the rule is skipped and no error is added. Clauses are appended to any IPropertyRule using the extension methods listed below.
| Clause Class | Description | Extensions |
|---|---|---|
DependsOnClause<TEntity, TProperty, TDependsOnProperty> |
Skips the rule when a specified sibling property has its default value or has already reported a validation error. | DependsOn(Expression<Func<TEntity, TDependsOnProperty>>) |
WhenClause<TEntity, TProperty> |
Skips the rule when a boolean condition or async predicate evaluates to false. |
When(bool), When(Func<bool>), When(Func<PropertyContext,bool>), When(PredicateAsync), WhenValue(Predicate<TProperty>), WhenHasValue(), WhenEntity(Predicate<TEntity>) |
Rules
Rules apply the actual validation logic to a property value. Each rule class is typically instantiated via the corresponding ValidationExtensions method(s). Rules inherit from PropertyRuleBase<TEntity, TProperty> and implement OnValidateAsync.
| Rule Class | Description | Extensions |
|---|---|---|
BetweenRule<TEntity, TProperty> |
Validates that a comparable value lies between two bounds (inclusive or exclusive). | Between(min, max), InclusiveBetween(min, max), ExclusiveBetween(min, max) |
CollectionRule<TEntity, TProperty, TItem> |
Validates an IEnumerable<T> collection: min/max count, duplicate detection (by Id, key, property, or equality), and optional per-item entity validation. |
Collection(with), Collection(maxCount), Collection(minCount, maxCount); With helpers: WithDuplicateIdCheck(), WithDuplicateKeyCheck(), WithDuplicatePropertyCheck(), WithDuplicateCheck() |
CommonRule<TEntity, TProperty> |
Applies a CommonValidator<TProperty> (or InlineValidator<TProperty>) to a property, enabling shared rule logic to be reused across multiple properties or validators. |
Common(commonValidator) |
ComparePropertyRule<TEntity, TProperty, TCompareProperty> |
Compares the property value against another property on the same entity using a CompareOperator; skips if the target property already has an error. |
CompareProperty(op, expression) |
CompareValueRule<TEntity, TProperty> |
Compares the property value against a supplied constant or function value using a CompareOperator. |
CompareValue(op, value), Equal(value), NotEqual(value), LessThan(value), LessThanOrEqualTo(value), GreaterThan(value), GreaterThanOrEqualTo(value) |
CompareValuesRule<TEntity, TProperty> |
Validates that the property value is equal to one of a supplied set of values; optionally replaces the value with the matched entry. | CompareValues(values), CompareValues(Func<context, values>) |
DecimalRule<TEntity> |
Validates decimal precision and scale, and optional sign constraint. Also covers IFloatingPoint<T> via PrecisionScale. |
Decimal(precision, scale), PrecisionScale(precision, scale) |
DictionaryRule<TEntity, TProperty, TKey, TValue> |
Validates an IDictionary<TKey,TValue>: min/max count and optional per-entry value validation. |
Dictionary(with), Dictionary(maxCount), Dictionary(minCount, maxCount) |
EmailRule<TEntity> |
Validates that a string is a valid e-mail address (via MailAddress.TryCreate) and optionally within a maximum length. |
Email(), Email(maxLength) |
EntityRule<TEntity, TProperty> |
Delegates validation of a complex child-entity property to a separate IValidatorEx<TProperty>; merges child errors into the parent context with prefixed property names. |
Entity(with), Entity(validator) |
EnumRule<TEntity, TProperty> |
Validates that a struct Enum value is defined (or within an optional allowed set). |
Enum(), Enum(allowed[]) |
EnumStringRule<TEntity> |
Validates that a string property can be parsed to a specified Enum type; configured via EnumWith fluent builder. |
Enum(Func<EnumWith, EnumWith>) (string overload) |
ErrorRule<TEntity, TProperty> |
Always emits the supplied error text; intended for use with a When/DependsOn clause to guard its execution. |
Error(text), Duplicate(), NotFound(), Invalid(), Immutable() |
InteropRule<TEntity, TProperty> |
Delegates validation to an external IValidator/IValidator<T> (e.g. a FluentValidation validator) and merges results into the CoreEx ValidationContext. |
Interop(getValidator), Interop(validator) |
MandatoryRule<TEntity, TProperty> |
Validates that the value is not null, not the default value, and/or not empty (string/collection). |
Mandatory(), NotNull(), NotEmpty() |
NullNoneEmptyRule<TEntity, TProperty> |
Validates that the value is null, default, or empty — the inverse of mandatory; configurable per mode. |
Null(), None(), Empty() |
NumericRule<TEntity, TProperty> |
Validates that a numeric value satisfies sign constraints (allows/disallows negatives). | Numeric(allowNegatives), Positive() |
ReferenceDataCodeCollectionRule<TEntity, TProperty> |
Validates that an IReferenceDataCodeCollection contains no invalid or inactive items. |
ReferenceDataCodes(allowInactive), AreValid(allowInactive) |
ReferenceDataCodeRule<TEntity> |
Validates that a string property represents a valid reference data code, resolving through the orchestrator; configured via ReferenceDataWith fluent builder. |
ReferenceData(Func<ReferenceDataWith, ReferenceDataWith>) (string overload) |
ReferenceDataRule<TEntity, TProperty> |
Validates that an IReferenceData property is valid (and optionally active). |
ReferenceData(allowInactive), IsValid(allowInactive) |
RuleSet<TEntity> |
Groups a block of IRootPropertyRule chains that only execute when a Predicate<ValidationContext<TEntity>> is true; wired into a validator via RuleSet(predicate, configure) on the fluent builder. |
(used via ValidatorBase<TEntity, TSelf>.RuleSet(predicate, configure)) |
StringRule<TEntity> |
Validates string length (min/max), regex pattern matching, or an exact length. | String(maxLength), String(min, max, regex), Matches(regex), Length(exact), MinimumLength(), MaximumLength() |
WildcardRule<TEntity> |
Validates that a string conforms to a CoreEx Wildcard pattern. |
Wildcard(), Wildcard(wildcard) |
Namespaces
| Namespace | Description | Documentation |
|---|---|---|
CoreEx.Validation.Abstractions |
Core interfaces, abstract base classes, and infrastructure types that underpin the validation framework: IValidatorEx, ValidatorBase, InlineValidator, ValueValidator, IPropertyContext, IValidationContext, and ValidationMessageItem. |
📖 README |
CoreEx.Validation.Clauses |
Conditional clause implementations (WhenClause, DependsOnClause) and the IPropertyClause interface. |
📖 README |
CoreEx.Validation.Rules |
All built-in rule implementations (MandatoryRule, StringRule, CollectionRule, etc.) and the IPropertyRule / PropertyRuleBase infrastructure. |
📖 README |
Related namespaces
CoreEx- DefinesValidationException,MessageItem,IValidationResult,LText,ExecutionContext, andWildcardconsumed throughout.CoreEx.RefData- ProvidesIReferenceDataandIReferenceDataCodeCollectionvalidated byReferenceDataRule,ReferenceDataCodeRule, andReferenceDataCodeCollectionRule.CoreEx.AspNetCore- ConvertsValidationExceptionraised byValidateAndThrowAsyncinto HTTP 400 responses with a structured error body.
AI Usage Guide
An AGENTS.md file is included with this package. AI coding assistants (GitHub Copilot, Claude, Cursor, etc.) that support workspace-injected package documentation will automatically surface concise usage guidance, code examples, and Do Not rules for this package without requiring a local CoreEx checkout.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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 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. |
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on CoreEx.Validation:
| Repository | Stars |
|---|---|
|
Avanade/Beef
The Business Entity Execution Framework (Beef) framework, and the underlying code generation, has been primarily created to support the industrialization of API development.
|
| Version | Downloads | Last Updated |
|---|---|---|
| 4.0.0-preview-1 | 68 | 6/20/2026 |
| 3.31.0 | 8,520 | 2/1/2025 |
| 3.30.2 | 251 | 12/11/2024 |
| 3.30.1 | 274 | 12/9/2024 |
| 3.30.0 | 5,031 | 11/21/2024 |
| 3.29.0 | 253 | 11/19/2024 |
| 3.28.0 | 339 | 11/9/2024 |
| 3.27.3 | 506 | 10/23/2024 |
| 3.27.2 | 230 | 10/17/2024 |
| 3.27.1 | 297 | 10/15/2024 |
| 3.27.0 | 272 | 10/11/2024 |
| 3.26.0 | 258 | 10/3/2024 |
| 3.25.6 | 290 | 10/2/2024 |
| 3.25.5 | 277 | 9/25/2024 |
| 3.25.4 | 280 | 9/24/2024 |
| 3.25.3 | 302 | 9/18/2024 |
| 3.25.2 | 266 | 9/17/2024 |
| 3.25.1 | 300 | 9/16/2024 |
| 3.25.0 | 284 | 9/10/2024 |
| 3.24.1 | 316 | 8/7/2024 |