Skip to content

FluentValidation

Reuse your existing AbstractValidator<T>. Borm runs it against the bound model and maps each failure onto its field by property path — including cross-field rules. Try entering 5+ years of experience and leaving the motivation short.

Live form
Job application

View source
@page "/fluent-validation"
@inject global::FluentValidation.IValidator<JobApplication> Validator

<BormView State="_state" OnValidSubmit="HandleSubmit" SubmitText="Apply" />

@code {
    private readonly JobApplication _model = new();
    private BormState _state = default!;

    protected override void OnInitialized()
    {
        var schema = BormBuilder.For<JobApplication>()
            .Title("Job application")
            .Field(x => x.FirstName, f => f.Label("First name"))
            .Field(x => x.LastName, f => f.Label("Last name"))
            .Field(x => x.Email)
            .Field(x => x.YearsExperience, f => f.Label("Years of experience"))
            .Field(x => x.DesiredSalary, f => f.Label("Desired salary"))
            .Field(x => x.Motivation, f => f.AsTextArea(4).Label("Why do you want this role?"))
            .Build();

        // Validation comes entirely from the FluentValidation validator.
        _state = new BormState(schema, new BormModelDataAccessor(_model))
            .UseFluentValidation(Validator);
    }

    private void HandleSubmit(BormState state)
    {
        var json = System.Text.Json.JsonSerializer.Serialize(_model,
            new System.Text.Json.JsonSerializerOptions { WriteIndented = true });
    }
}
An unhandled error has occurred. Reload 🗙