vNext.BlazorComponents.FluentValidation 1.1.3

dotnet add package vNext.BlazorComponents.FluentValidation --version 1.1.3                
NuGet\Install-Package vNext.BlazorComponents.FluentValidation -Version 1.1.3                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="vNext.BlazorComponents.FluentValidation" Version="1.1.3" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add vNext.BlazorComponents.FluentValidation --version 1.1.3                
#r "nuget: vNext.BlazorComponents.FluentValidation, 1.1.3"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install vNext.BlazorComponents.FluentValidation as a Cake Addin
#addin nuget:?package=vNext.BlazorComponents.FluentValidation&version=1.1.3

// Install vNext.BlazorComponents.FluentValidation as a Cake Tool
#tool nuget:?package=vNext.BlazorComponents.FluentValidation&version=1.1.3                

FluentValidation

A battle tested library for using FluentValidation with Blazor that supports async validation, severity levels and more.

For introduction, see this blog post

Live demo can be found here: https://blazorrepl.telerik.com/GQYpbvbP37ENDltY58

Build & Test Main

Nuget

Installing

You can install from Nuget using the following command:

Install-Package vNext.BlazorComponents.FluentValidation

Or via the Visual Studio package manger.

Basic Usage

Start by add the following using statement to your root _Imports.razor.

@using vNext.BlazorComponents.FluentValidation

You can then use it as follows within a EditForm component.

<EditForm Model="@Person" OnValidSubmit="@SubmitValidForm">
    <FluentValidationValidator />
    <ValidationSummary />

    <p>
        <label>Name: </label>
        <InputText @bind-Value="@Person.Name" />
    </p>

    <p>
        <label>Age: </label>
        <InputNumber @bind-Value="@Person.Age" />
    </p>

    <p>
        <label>Email Address: </label>
        <InputText @bind-Value="@Person.EmailAddress" />
    </p>

    <button type="submit">Save</button>

</EditForm>

@code {
    Person Person { get; set; } = new Person();

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

Discovering Validators

The component locates validators using IValidatorFactory optional service. The DefaultValidatorFactory implementation check for validators registered with DI first.

If it finds multiple validators, validators in the same assembly and namespace are takes precedence. If it can't find any, it will then try scanning the applications assemblies

You can override default behaviour on by registering IValidatorFactory service:

   services.AddSingleton<IValidatorFactory>(new DefaultValidatorFactory { DisableAssemblyScanning = false })

or per FluentValidationValidator component

  <FluentValidationValidator ValidatorFactory="customValidatorFactory" />

  @code {
      IValidatorFactory customValidatorFactory = new MyCustomValidatorFactory();
  }

See DefaultValidatorFactory.cs for more info.

Validating Complex Models

class PersonValidator : AbstractValidator<Person>
{
        public PersonValidator() {
            RuleFor(x => x.Name).NotEmpty();
            RuleFor(x => x.Address).SetValidator(new AddressValidator()); //must be set explicitelly
        }
}
class AddressValidator: AbstractValidator<Address> //should be separate class
{
        public AddressValidator() {
            RuleFor(x => x.Street).NotEmpty();
        }  
}

Blazor performs two kinds of validation:

  1. Model validation triggered by EditContext.Validate() which is called usually on form submit
  2. FieldIdentifier validation triggered by EditContext.NotifyValidationStateChanged() which is called automatically, when user edits inputs.

When Field validation is triggered, FluentValidator will create validator based on FieldIdentifier.Model, which might be different from EditContext.Model in case of complex models.

Consider following example:

<EditContext Model="Person" OnValidSubmit="ValidSubmitted">
    <InputText @bind-Value="Person.Name" />
    <InputText @bind-Value="Person.Address.Street" />
    <button type="submit" />
</EditContext>
  1. When user edits Person.Name, FluentValidator validates the property using IValidator<Person>

  2. When user edits Person.Address.Street, FluentValidator validates the property using IValidator<Address>

  3. When user clicks submit button, FluentValidator validates the Person class using IValidator<Person>.

    However, IValidator<Address> will not be automatically used, unless it is explicitelly defined for Address property in IValidator<Person>.

Common mistakes:

Address street is validated only when user edits the input, but not on submit:

class PersonValidator : AbstractValidator<Person>
{
        public PersonValidator() {
            RuleFor(x => x.Name).NotEmpty();
        }
}
class AddressValidator: AbstractValidator<Person>
{
        public AddressValidator() {
            RuleFor(x => x.Street).NotEmpty();
        }  
}

Street is validated only on submit, but not when user edits the input:

class PersonValidator : AbstractValidator<Person>
{
        public PersonValidator() {
            RuleFor(x => x.Name).NotEmpty();
            RuleFor(x => x.Address.Street).NotEmpty();
        }
}
Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.1.3 9,312 2/22/2024
1.1.2 133 2/20/2024
1.1.1 33,975 9/9/2022
1.1.0 6,994 7/18/2022
1.0.0 3,358 3/16/2022
0.5.0 1,555 10/18/2021