Advanced validation in Blazor using FluentValidation

You are probably familiar with the great FluentValidation validation library - defacto industry standard for any advanced validation scenarios in .NET.

There has been a few attempt to integrate FluentValidation with Blazor Forms:Blazored.FluentValidation, Accelist.FluentValidation.Blazor, just to name few, however none supports all of the advances scenarios like asynchronous validation, validation severity, rulesets.

I wonder why would anybody use FluentValidation in Blazor when it's advanced features are unsupported.

To solve this, I have released vNext.BlazorComponents.FluentValidation nuget package.

It's based on Chris Sainty's BlazorValidator with backward compatible API, but I have added support for:

  1. Asynchronous validation
async Task OnSubmited(EditContext editContext)
{
    editContext.Validate();
    var validationResult = await editContext.GetValidationResultAsync(); //make sure async valiation completes
    if (validationResult.IsValid)
    {
        await JS.InvokeVoidAsync("alert", "Form Submitted Successfully!");
    }
}
asynchronous validation

2. Validation Severity

<FluentValidationValidator Severity="Severity.Error" />
ignore warnings

or alternatively:

bool overrideWarnings = false;

async Task OnSubmited(EditContext editContext)
{
    editContext.Validate();
    var validationResult = await editContext.GetValidationResultAsync();
    bool isValid = validationResult.IsValid;
    if (overrideWarnings) 
    {
       isValid = validationResult.Any(e => e.Severity == Severity.Error);
    }
    if (isValid)
    {
        await JS.InvokeVoidAsync("alert", "Form Submitted Successfully!");
    }
}

3. Custom validator factory:

<FluentValidationValidator ValidatorFactory="CreateValidator" />
IValidator CreateValidator(ValidatorFactoryContext ctx)
{
    if (ctx.Model == Person.Address)
    {
        //set custom flags on the validotor
        return new AddressValidator() { CheckPostalCode = false };
    }
    return (IValidator)ctx.ServiceProvider.GetService(ctx.ValidatorType);
}

4. Designed for extensibility

You can extent the FluentValidator component by inheriting from it and override virtual methods

virtual IValidator? GetValidator(FieldIdentifier fieldIdentifier = default);

virtual string MapValidationFailureToMessage(ValidationFailure failure, ValidationResult result, ValidationContext<object> validationContext);

virtual ValidationContext<object> CreateValidationContext(IValidator validator, FieldIdentifier fieldIdentifier = default);

virtual void ConfigureValidationStrategy(ValidationStrategy<object> options, IValidator validator, FieldIdentifier fieldIdentifier = default)

Let me know if you need some other feature, I will surely consider adding it.