Skip to main content

Migration Guides

v10.1.0 → v10.2.0​

This release is additive. It adds MustBeValidIban() and updates the RA.Utilities.Core.ValueObjects dependency to 10.2.0, which introduces the IBAN value object. No existing rule, signature, or behavior changed.

What's new​

Type / ruleChange
RA.Utilities.Application.Validation.Extensions.IbanValidatorExtensionsNew
MustBeValidIban()New FluentValidation rule for string? IBAN properties
RA.Utilities.Core.ValueObjects dependencyUpdated to 10.2.0 (adds IBAN)
FluentValidation dependencyUnchanged (12.1.1)

Why this change?​

IBAN is a new value object in RA.Utilities.Core.ValueObjects 10.2.0. The package's other value-object rules already validate through the domain types, so request validation and the domain stay aligned only if an IBAN rule exists too.

MustBeValidIban() follows the same design as MustBeValidCurrency(), MustBeValidEmail(), and MustBeValidSsn():

  • It constructs new IBAN(value) behind the scenes and fails the rule when the constructor throws.
  • It normalizes casing and grouping separators, and enforces the 13–34 character structure plus the ISO 7064 mod-97 checksum.
  • It fails on null, empty, and whitespace input, so the rule doubles as a required check.
  • It reports the generic BadRequestException message ("The request is invalid."); use WithMessage(...) for a property-specific message.

Migration steps​

1. Upgrade the package​

dotnet add package RA.Utilities.Application.Validation --version 10.2.0

2. Add the rule where IBANs are accepted​

using RA.Utilities.Application.Validation.Extensions;

public sealed class CreatePaymentValidator : AbstractValidator<CreatePaymentRequest>
{
public CreatePaymentValidator()
{
RuleFor(x => x.Iban).MustBeValidIban();
}
}

3. Decide whether the IBAN is required​

The rule fails on missing values. If the field is optional, apply a condition:

RuleFor(x => x.Iban)
.MustBeValidIban()
.When(x => !string.IsNullOrWhiteSpace(x.Iban));

4. Keep country-length checks separate​

The rule validates structure and the checksum, not the length required by each country's registry. If your domain needs that, validate it separately and report BaseErrorCode.IbanLength — see IbanValidatorExtensions.

Breaking changes​

None. Existing rules and ValidationUtilities signatures are unchanged.


v10.0.1 → v10.1.0​

Breaking Change: ValidateAsync now requires a CancellationToken​

ValidationUtilities.ValidateAsync has a new third parameter — a CancellationToken — and it has no default, so existing two-argument calls no longer compile (CS7036). Pass CancellationToken.None if you have no token to propagate, or forward the token from your request pipeline.

Before (10.0.1):

ValidationFailure[] failures = await ValidationUtilities.ValidateAsync(request, validators);

After (10.1.0):

ValidationFailure[] failures = await ValidationUtilities.ValidateAsync(request, validators, cancellationToken);

The token is forwarded to every validator, so validators with async rules honour cancellation. The ValidationBehavior in RA.Utilities.Feature already forwards the request token.

Other Changes (non-breaking)​

  • New rules: MustBeValidCurrency(), MustBeValidEmail() and MustBeValidSsn() validate through the Currency, Email and SSN value objects of RA.Utilities.Core.ValueObjects — any input the value object rejects fails the rule. Additive only.
  • New dependency: RA.Utilities.Core.ValueObjects (10.1.0) — pulled in transitively, no action needed.
  • Extension classes refactored to C# 14 extension members: CurrencyValidatorExtensions, EmailValidatorExtensions and SsnValidatorExtensions are now implemented as C# 14 extension members. Method names, parameters, and call-site syntax are unchanged.

v10.0.0 → v10.0.1​

Breaking Change: ValidationErrors → ValidationError​

CreateValidationErrorResult now maps failures to the renamed ValidationError type from RA.Utilities.Core.Exceptions 10.0.4 (the class represents a single error, hence the singular name). The BadRequestException.Errors array is now ValidationError[].

If you only consume exception.Errors and never name the old type, you don't need to change anything. Code that references ValidationErrors by name must be updated.

Why this change?​

  • The rename aligns with RA.Utilities.Core.Exceptions 10.0.4, where ValidationErrors was renamed to ValidationError and its constructor now requires the error message.
  • The old collection-initializer pattern could produce errors without a message; the new constructor guarantees one.

What changed​

Before (10.0.0)After (10.0.1)
Element typeValidationErrorsValidationError
Constructorparameterless + object initializerValidationError(string errorMessage)
Messageoptionalrequired

Migration Steps​

1. Rename references to the error type​

Before:

ValidationErrors error = exception.Errors[0];
var error = new ValidationErrors { ErrorMessage = "Something is wrong." };

After:

ValidationError error = exception.Errors[0];
var error = new ValidationError("Something is wrong.");

2. Update the RA.Utilities.Core.Exceptions dependency​

The new payload type lives in RA.Utilities.Core.Exceptions 10.0.4+. Upgrading this package pulls it in transitively; if you reference Core.Exceptions explicitly, update it too. See the Core.Exceptions migration guide for the full rename details.

Behavior Change: null currency values now pass​

In 10.0.0, MustMatchesCurrencyFormat() rejected null values with the format error message (FluentValidation 12 runs Must on null). In 10.0.1, null passes the format rule — requiredness is the job of NotNull() / NotEmpty().

If you relied on the old behavior to reject null currencies, make the requirement explicit:

Before (10.0.0):

RuleFor(x => x.Currency).MustMatchesCurrencyFormat(); // null → error

After (10.0.1):

RuleFor(x => x.Currency).NotNull().MustMatchesCurrencyFormat(); // null → error

Bug Fix: duplicate failures from parallel validators​

10.0.0 shared a single ValidationContext across all validators in ValidateAsync, so each validator's result contained every validator's failures — one failing rule could appear once per registered validator (with a data race on top when validators were genuinely async). 10.0.1 creates a fresh context per validator. No migration is required; if you worked around the duplicates by de-duplicating failures, that workaround can be removed.

Full Changelog​

See the package release notes for a complete version history.