RA.Utilities.Application.Validation
· 4 min read
Version 10.2.0
Feature release: adds MustBeValidIban() so request validation can validate IBANs through the new IBAN value object, keeping the package's rule set aligned with RA.Utilities.Core.ValueObjects 10.2.0.
✨ New Features
MustBeValidIban()(inRA.Utilities.Application.Validation.Extensions): aCustomrule forstring?properties that constructsnew IBAN(value)behind the scenes. It enforces the 13–34 character structure and the ISO 7064 mod-97 checksum, normalizes casing and grouping separators ("gb82 west 1234 5698 7654 32"passes), and fails onnull, empty, and whitespace input.- Because it validates through the value object, request validation and the domain share one IBAN rule — no duplicate format logic in validators.
public sealed class CreatePaymentValidator : AbstractValidator<CreatePaymentRequest>
{
public CreatePaymentValidator()
{
RuleFor(x => x.Iban).MustBeValidIban();
}
}
📝 Notes
- The failure message is the generic
BadRequestExceptionmessage ("The request is invalid."), like the otherMustBeValid*rules; chainWithMessage(...)for a property-specific message. - The rule does not check per-country lengths or SWIFT registry membership. Validate country-specific lengths separately and report
BaseErrorCode.IbanLengthwhen your domain requires it. - Make the field optional with
.When(x => !string.IsNullOrWhiteSpace(x.Iban)); the rule otherwise doubles as a required check.
📦 Dependencies
RA.Utilities.Core.ValueObjects10.2.0 — addsIBAN.FluentValidation12.1.1 (unchanged).RA.Utilities.Core.Exceptions(unchanged).
⚠️ Breaking Changes
None. Existing rules and ValidationUtilities signatures are unchanged.
Version 10.1.0
Feature release: adds FluentValidation rules that validate through the value objects of RA.Utilities.Core.ValueObjects — so request validation and the domain share one set of rules — and adds CancellationToken support to ValidationUtilities.ValidateAsync.
✨ New Features
MustBeValidCurrency(),MustBeValidEmail()andMustBeValidSsn()(inRA.Utilities.Application.Validation.Extensions):Customrules forstring?properties that construct the matching value object behind the scenes. Any input the value object rejects fails the rule for the property path.- Because the value object constructors reject
null, empty and whitespace input, these rules also fail on missing values — unlikeMustMatchesCurrencyFormat(), wherenullpasses and requiredness is left toNotNull()/NotEmpty(). - The failure message is the generic
BadRequestExceptionmessage ("The request is invalid."), not the value object's specific message; chainWithMessage(...)for a property-specific message.
public class RegisterUserValidator : AbstractValidator<RegisterUserRequest>
{
public RegisterUserValidator()
{
RuleFor(x => x.Email).MustBeValidEmail();
RuleFor(x => x.Currency).MustBeValidCurrency();
RuleFor(x => x.Ssn).MustBeValidSsn();
}
}
⚠️ Breaking Changes
ValidationUtilities.ValidateAsyncnow requires aCancellationToken: the new third parameter has no default, so existing two-argument calls no longer compile — passCancellationToken.Noneor forward the request's token. The token is passed to every validator, enabling cooperative cancellation. Migration: see the migration guide.
📝 Improvements
- Faster validation orchestration:
ValidateAsyncreturns an empty array immediately when no validators are registered, awaits a single validator directly instead of going throughTask.WhenAll, no longer re-materializes validator collections that are already arrays (the standard DI case), and usesConfigureAwait(false)throughout.
📦 Dependencies
- New dependency on
RA.Utilities.Core.ValueObjects(10.1.0) — the new rules constructCurrency,EmailandSSNinstances to validate input.RA.Utilities.Core.Exceptionsremains a direct dependency forValidationUtilities.CreateValidationErrorResult.
Version 10.0.1
Bug-fix release: corrects duplicated validation failures from parallel validators, fixes null handling in MustMatchesCurrencyFormat, and adopts the renamed ValidationError type from RA.Utilities.Core.Exceptions 10.0.4.
🐛 Bug Fixes
- Fixed duplicate and cross-contaminated validation failures:
ValidateAsyncnow creates a freshValidationContextper validator instead of sharing one acrossTask.WhenAll. In 10.0.0 the shared context held a single mutable failure list, so every validator's result contained all failures (one failing rule appeared once per registered validator), with a data race on top when validators were genuinely async. - Fixed
MustMatchesCurrencyFormatrejecting null: null values now pass the format rule. FluentValidation 12 runsMuston null, so in 10.0.0 an optional currency field failed with the format message. ChainNotNull()/NotEmpty()for required currencies.
⚠️ Breaking Changes
ValidationErrors→ValidationError:CreateValidationErrorResultnow maps failures to the renamedValidationErrortype (fromRA.Utilities.Core.Exceptions10.0.4), whose constructor requireserrorMessage. Migration: rename references toValidationErrorsand pass the message to the constructor — see the migration guide.
📝 Improvements
- Added test coverage — 24 tests covering
ValidationUtilitiesandCurrencyValidatorExtensions(parallel aggregation, failure mapping, currency format edge cases).
Version 10.0.0
- Initial release of the
RA.Utilities.Application.Validationpackage. - Provides utility validators using
FluentValidationfor incoming requests.