ExtendedFluentValidation
Extends FluentValidation with some more opinionated rules and extensions.
See Milestones for release notes.
Nuget
https://nuget.org/packages/ExtendedFluentValidation/
Extra Rules
Nullability
It leverages nullability information to make all non-nullable reference properties to be required.
Dates
DateTime
, DateTimeOffset
, and DateOnly
cannot be MinValue
.
Strings
String cannot be String.Empty
or only white-space.
Guids
Guids cannot be Guid.Empty
.
Lists/Collections
Lists and Collection cannot be empty.
Usage
There are two ways of applying the extended rules.
ExtendedValidator
Using a base class ExtendedValidator
:
class PersonValidatorFromBase :
ExtendedValidator<Person>
{
public PersonValidatorFromBase()
{
//TODO: add any extra rules
}
}
AddExtendedRules
Using an extension method AddExtendedRules
:
class PersonValidatorNonBase :
AbstractValidator<Person>
{
public PersonValidatorNonBase() =>
this.AddExtendedRules();
//TODO: add any extra rules
}
Equivalent
The above are equivalent to:
public class Person
{
public Guid Id { get; set; }
public string FirstName { get; set; }
public string? MiddleName { get; set; }
public string FamilyName { get; set; }
public DateTimeOffset Dob { get; set; }
}
class PersonValidatorEquivalent :
AbstractValidator<Person>
{
public PersonValidatorEquivalent()
{
RuleFor(_ => _.Id)
.NotEqual(Guid.Empty);
RuleFor(_ => _.FirstName)
.NotEmpty();
RuleFor(_ => _.MiddleName)
.SetValidator(new NotWhiteSpaceValidator<Person>());
RuleFor(_ => _.FamilyName)
.NotEmpty();
RuleFor(_ => _.Dob)
.NotEqual(DateTimeOffset.MinValue);
}
}
Shared Rules
Given the following models:
public interface IDbRecord
{
public byte[] RowVersion { get; }
public Guid Id { get; }
}
public class Person :
IDbRecord
{
public Guid Id { get; set; }
public string Name { get; set; }
public byte[] RowVersion { get; set; }
}
It is desirable to have the rules for IDbRecord
defined separately, and not need to duplicate them for every implementing class. This can be done using shares rules.
Configure any shared rules at startup:
[ModuleInitializer]
public static void Init() =>
ValidatorExtensions.SharedValidatorFor<IDbRecord>()
.RuleFor(record => record.RowVersion)
.Must(rowVersion => rowVersion?.Length == 8)
.WithMessage("RowVersion must be 8 bytes");
The PersonValidator
used only the standard rules, so needs no constructor.
class PersonValidator :
ExtendedValidator<Person>;
The above is equivalent to:
class PersonValidatorEquivalent :
AbstractValidator<Person>
{
public PersonValidatorEquivalent()
{
RuleFor(_ => _.Id)
.NotEqual(Guid.Empty);
RuleFor(_ => _.Name)
.NotEmpty();
RuleFor(_ => _.RowVersion)
.NotNull()
.Must(rowVersion => rowVersion?.Length == 8)
.WithMessage("RowVersion must be 8 bytes");
}
}
Icon
Pointed Star designed by Eliricon from The Noun Project.