Not yet assessed
Review the original instructions and requested permissions before installing.
No security review is available for this catalog entry yet.
Create and extend CoreEx application-layer validators, including nested entity and collection rules.
Create or modify a CoreEx validator in the Application layer. USE FOR: new Validator<T,TSelf> (no injection), new Validator<T> with constructor injection, AbstractValidator<T,TSelf> (FluentValidation-style), adding rules to an existing validator, nested entity/collection/dictionary validators. DO NOT USE FOR: domain invariants in aggregates, FluentValidation NuGet package, Infrastructure-layer checks.
Review the original instructions and requested permissions before installing.
No security review is available for this catalog entry yet.
How clearly the skill guides your agent, how complete its workflow is, and how you can check the outcome.
No quality assessment is available for this catalog entry yet.
Original instructions from the publisher’s SKILL.md
<!--
AI workflow asset — dual-audience notice:
- In the Avanade/CoreEx repository: this file is the authored source. Edit it here.
- In a consumer repository: this file was generated by `dotnet new coreex-ai` (or refreshed via
`dotnet new coreex-ai --force` / the `/coreex-docs-sync` skill). Do not hand-edit it directly —
propose the change upstream in Avanade/CoreEx instead, then refresh once it is released.
-->
# CoreEx: Validator
Guides you through creating or modifying a CoreEx validator (`Application/Validators/`) for a contract or request type. Covers declarative rules, ref-data validation, async database checks, collection and dictionary validators.
## When to Use
- New validator for a contract or request type (no database calls needed)
- New validator that requires a repository or other Application-layer dependency
- Adding property rules or an async check to an existing validator
- Nested validator for a sub-property (`.Entity()`), a collection, or a dictionary
- Switching to FluentValidation-compatible `AbstractValidator` syntax
## When Not to Use
- Domain invariants (aggregates, entities, value objects) — those belong in the Domain layer
- Infrastructure-level data checks that are not accessed via an Application-layer interface
- `FluentValidation` NuGet package — `AbstractValidator` here is `CoreEx.Validation.AbstractValidator`
## Quick Reference
**Clarifying questions to ask before writing any code:**
1. Does the validator need a constructor-injected dependency (e.g. a repository)? (determines base class)
2. Which properties need validation? (list upfront — batch type resolution, don't interrupt per-property)
3. Are any ref-data properties required? Optional? (`.Mandatory().IsValid()` vs `.IsValid()`)
4. Are any checks async (e.g. confirming an entity exists in the database)?
5. Does the user prefer FluentValidation-style `RuleFor(x => ...)` syntax?
**Base class decision:**
| Situation | Base class | Notes |
|---|---|---|
| No injection needed | `Validator<T, TSelf>` | Exposes `Default` singleton; invoke via `.Default.ValidateAndThrowAsync(...)` |
| Constructor injection needed | `Validator<T>` | No `Default`; instantiate at the call site with already-injected dependencies: `new {Name}Validator(_dep).ValidateAndThrowAsync(...)` |
| FluentValidation-style preferred | `AbstractValidator<T, TSelf>` | `RuleFor(x => ...)` / `NotEmpty()` / `IsValid()` — still CoreEx; has `Default` |
**Key rules at a glance:**
- Ref-data: `.IsValid()` on the **navigation property** (`Gender`), never on `*Code` string
- `Mandatory()` on a non-nullable value type errors on `default` (`0`, `MinValue`) — use a range rule if `0` is valid
- Runtime-computed thresholds: use delegate overloads (`.LessThanOrEqualTo(_ => ...)`) — prefer over `OnValidateAsync` imperative logic
- `context.HasErrors` guard before async I/O; `context.HasError(x => x.Prop)` for per-property guards
- `context.AddError(x => x.Prop, ...)` — member-access expression, never `nameof(...)`
- Message text argument is a `{2}` suffix substitution — not a full sentence; use `.Error("...")` to override the whole message
- **Always generate or update the matching `{Validator}Tests`** in `*.Test.Unit/Validators/` — cover conditional/business rules and cross-field logic thoroughly, plus a representative error/success pair for simple rules; skip dedicated boundary tests for framework-guaranteed constraints like length rules (`MaximumLength`/`MinimumLength`/`Length`/`String`)
For full workflow, rule reference, and code examples see [`references/workflow.md`](references/workflow.md).
## Key References
- [`/.github/instructions/coreex-validators.instructions.md`](/.github/instructions/coreex-validators.instructions.md) — full rule set, comparison operators, localization, DependsOn, DI registration
- [`/.github/instructions/coreex-tests.instructions.md`](/.github/instructions/coreex-tests.instructions.md) — validator unit test conventions: `Test.Scoped`, `AssertErrors`, expected message text
- Related skills: [`coreex-app-service`](../coreex-app-service/SKILL.md) (invokes the validator), [`coreex-policy`](../coreex-policy/SKILL.md) (async I/O guard sibling for checks a validator cannot do), [`coreex-contract`](../coreex-contract/SKILL.md) (the type being validated)
- Illustrative examples (CoreEx sample — not present in your project):
- [`ProductValidator` + `MovementRequestValidator`](https://github.com/Avanade/CoreEx/tree/main/samples/src/Contoso.Products.Application/Validators) — simple, plus injection + dictionary + async
- [Shopping validators](https://github.com/Avanade/CoreEx/tree/main/samples/src/Contoso.Shopping.Application/Validators) — `AbstractValidator` style, plain request validators
- [`OrderValidator`](https://github.com/Avanade/CoreEx/tree/main/samples/src/Contoso.Orders.Application/Validators) — collection validator