Skip to main content

SsnValidatorExtensions

Namespace: RA.Utilities.Application.Validation.Extensions

SsnValidatorExtensions adds a reusable FluentValidation rule that validates a string property through the SSN value object of RA.Utilities.Core.ValueObjects — so request validation and the domain share one set of SSN rules.

🎯 Purpose and Design​

1. Value-Object-Backed Rule​

MustBeValidSsn chains onto any string rule and validates the value by constructing an SSN instance behind the scenes:

public class RegisterUserValidator : AbstractValidator<RegisterUserRequest>
{
public RegisterUserValidator()
{
RuleFor(x => x.Ssn).MustBeValidSsn();
}
}

Any input the SSN value object rejects fails the rule for that property path: null, empty or whitespace, values over 10 characters, and values that don't match the ^[A-Z][0-9]{8}[A-Z]$ format (letter + 8 digits + letter).

The rule is declared as a C# 14 extension member on IRuleBuilder<T, string>; the calling syntax is unchanged.

2. Requiredness Is Enforced​

Because the SSN constructor rejects null, empty, and whitespace input, this rule also fails on missing values — the value doubles as a required check.

3. Failure Message​

The rule surfaces the BadRequestException message of the value object — the generic "The request is invalid." — rather than the specific validation detail. Chain WithMessage to provide a property-specific message:

RuleFor(x => x.Ssn)
.MustBeValidSsn()
.WithMessage("'{PropertyName}' must be a valid SSN.");

✔️ Valid vs Invalid​

ValueResult
"J01234567R"✅ Valid
" j01234567r "✅ Valid (trimmed and upper-cased to J01234567R)
null❌ Invalid (unlike shape-only format rules)
"" / " "❌ Invalid
"0123456789" (no letters)❌ Invalid
"J0123456R" (7 digits)❌ Invalid

🧠 Summary​

SsnValidatorExtensions delegates SSN validation to the SSN value object, keeping request validation and domain rules in sync. Unlike shape-only format rules, it fails on missing values and reports failures with the generic BadRequestException message.