Avanade

coreex-validator

"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."

Avanade 28 8 Actualitzat fa 1 setm.

Recursos

1
GitHub

Instal·la

npx skillscat add avanade/coreex/coreex-validator

Instal·la des del registre de SkillsCat.

SKILL.md

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
  • External HTTP response-contract validation — use coreex-adapter; small client-only rules belong inline in the Infrastructure client, not Application/Validators/
  • Other 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`.

Key References