Skip to main content
Version: 0.2.x (0.2.1)

Use with FluentValidation

A command or an inbound message often carries raw text rather than value objects. Its validator should not state the length, the pattern and the check-digit rule of an IBAN a second time: it should defer to the type that owns them, and report the same error codes as the rest of the system.

dotnet add package AdCodicem.ValueObjects.FluentValidation

Text that must become a value object​

public sealed class ImportAccountValidator : AbstractValidator<ImportAccountRequest>
{
public ImportAccountValidator()
{
RuleFor(request => request.Iban)
.NotEmpty()
.MustParseAs(typeof(Iban));
}
}

MustParseAs runs the type's own parsing: normalization, the declared rules, the validator hook. A failure carries the value object's error code — value_object.invalid_format for a wrong check digit — as the FluentValidation ErrorCode.

The type is passed as a Type rather than a type argument so the rule stays readable: C# cannot infer one type argument while another is given explicitly.

An underlying value, without building the value object​

RuleFor(request => request.Amount).MustSatisfy<TransferRequest, Amount, decimal>();

MustSatisfy checks a raw underlying value against the rules of a value object without constructing one.

An uninitialized value object​

RuleFor(command => command.Account).NotDefault<TransferCommand, Iban, string>();

NotDefault catches the one thing a struct value object cannot rule out by itself: an instance that was never constructed, arriving from a place the VO0010 analyzer cannot see — a deserializer of another library, reflection, an array element.

Returning the codes​

The codes reach an API client if you put them in the response. ASP.NET Core shows how to return them under the same errorCodes member that model binding uses.