Skip to main content

Authoring rules

Fluent definitions

Inherit ValidatorDefinition<T> and override Configure:

[ValiantValidator]
public sealed partial class ProductValidator : ValidatorDefinition<Product>
{
public override void Configure(ValidationContext<Product> context)
{
context.Property(product => product.Name)
.Required()
.LengthBetween(3, 80);

context.Property(product => product.Price)
.GreaterThan(0m);
}
}

The instance method also works naturally with constructor-injected dependencies and reusable validators.

Attribute definitions

Derive from ValidatorDefinition<T> to read Valiant validation attributes from the model:

[ValiantValidator]
public sealed partial class ProductValidator : ValidatorDefinition<Product>;

public sealed class Product
{
[Required("NameRequired", "Enter a product name.")]
[LengthBetween(3, 80)]
public string? Name { get; init; }

[GreaterThan(0)]
public decimal Price { get; init; }
}

These are attributes from Valiant.Validation, not Data Annotations. Fluent and attribute rules use the same generated checks and metadata.

Custom predicates

Use Satisfies for a rule that is clearer as code:

context.Property(order => order.Reference)
.Satisfies(
value => value is null || value.StartsWith("ORD-", StringComparison.Ordinal),
code: "ReferenceFormat",
message: "Reference must start with ORD-.");

Async predicate overloads are available for work that accepts a cancellation token.

Conditions

Apply a condition to a property chain:

context.Property(request => request.InviteCode)
.Required()
.When(request => request.RequiresInvite);

For larger branches, use normal C# control flow. See Composition and control flow.

Codes, messages, and severity

Every built-in check accepts optional code, message, and severity arguments:

context.Property(user => user.DisplayName)
.MaxLength(
40,
code: "DisplayNameLong",
message: "Display name is longer than 40 characters.",
severity: ValiantSeverity.Warning);

ValidationResult.Errors determine IsValid. Warnings and Infos are preserved separately for callers that want non-blocking feedback.