Instead of using the DataAnnotationValidator in Blazor, you can use FluentValidation to implement form validation. FluentValidation is a common validation library for.NET Core that offers a few advantages over the built-in DataAnnotations validation library, such as a larger set of rules, simpler setup, and extensibility.
To use fluent validation in a Blazor application:
-
Create a Blazor application using the link.
-
Install the “FluentValidation” package using the NuGet package manager.
-
Create a new folder named FluentValidation in the main application and add the following *.cs files – Employee, EmployeeValidator, FluentValidationValidator to it as shown below.

-
Add a model Employee class name in the Employee.cs file.
namespace {AppName}.FluentValidation { public class Employee { public string Name { get; set; } public string Organization { get; set; } } } -
To write a model validator, you must create a EmployeeValidator class that is inherited from the AbstractValidator<Employee> and then add all the validation rules for the respective model to the constructor.
using FluentValidation; namespace {AppName}.FluentValidation { public class EmployeeValidator : AbstractValidator<Employee> { public EmployeeValidator() { RuleFor(p => p.Name).NotEmpty().WithMessage("You must enter a valid name."); RuleFor(p => p.Name).MaximumLength(20).WithMessage("The name cannot be more than 20 characters long."); RuleFor(p => p.Organization).NotEmpty().WithMessage("You must enter a valid organization name."); } } } -
In FluentValidationValidator.cs, create a new validator component named FluentValidationValidator to replace DataAnnonationsValidator, and add the code below to it.
The FluentValidationValidator receives an EditContext as a cascading parameter and hooks into the EditContext’s OnFieldChanged and OnValidationRequested events to know when something is happening in the UI. It can add or remove validation messages from a ValidationMessageStore at any time.using System; using FluentValidation; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Forms; namespace {AppName}.FluentValidation { public class FluentValidationValidator<TValidator> : ComponentBase where TValidator : IValidator, new() { private readonly static char[] separators = new[] { '.', '[' }; private TValidator validator; [CascadingParameter] private EditContext EditContext { get; set; } protected override void OnInitialized() { validator = new TValidator(); var messages = new ValidationMessageStore(EditContext); /* Re-validate when any field changes or when the entire form requests validation.*/ EditContext.OnFieldChanged += (sender, eventArgs) => ValidateModel((EditContext)sender, messages); EditContext.OnValidationRequested += (sender, eventArgs) => ValidateModel((EditContext)sender, messages); } private void ValidateModel(EditContext editContext, ValidationMessageStore messages) { var context = new ValidationContext<object>(editContext.Model); var validationResult = validator.Validate(context); messages.Clear(); foreach (var error in validationResult.Errors) { var fieldIdentifier = ToFieldIdentifier(editContext, error.PropertyName); messages.Add(fieldIdentifier, error.ErrorMessage); } editContext.NotifyValidationStateChanged(); } private static FieldIdentifier ToFieldIdentifier(EditContext editContext, string propertyPath) { var obj = editContext.Model; while (true) { var nextTokenEnd = propertyPath.IndexOfAny(separators); if (nextTokenEnd < 0) { return new FieldIdentifier(obj, propertyPath); } var nextToken = propertyPath.Substring(0, nextTokenEnd); propertyPath = propertyPath.Substring(nextTokenEnd + 1); object newObj; if (nextToken.EndsWith("]")) { nextToken = nextToken.Substring(0, nextToken.Length - 1); var prop = obj.GetType().GetProperty("Item"); var indexerType = prop.GetIndexParameters()[0].ParameterType; var indexerValue = Convert.ChangeType(nextToken, indexerType); newObj = prop.GetValue(obj, new object[] { indexerValue }); } else { var prop = obj.GetType().GetProperty(nextToken); if (prop == null) { throw new InvalidOperationException($"Could not find property named {nextToken} in object of type {obj.GetType().FullName}."); } newObj = prop.GetValue(obj); } if (newObj == null) { return new FieldIdentifier(obj, nextToken); } obj = newObj; } } } } -
Add the following code to the Index.razor page to perform fluent validation using the FluentValidationValidator component and its model validator (EmployeeValidator) in the EditForm component.
@page "/" @using {AppName}.FluentValidation; <EditForm Model="employee" OnValidSubmit="SubmitForm"> <FluentValidationValidator TValidator="EmployeeValidator" /> <ValidationSummary /> <div class="form-group"> <label for="name">Name:</label> <InputText @bind-Value="employee.Name" class="form-control" id="name" /> </div> <div class="form-group"> <label for="age">Organization:</label> <InputText @bind-Value="employee.Organization" class="form-control" /> </div> <button type="submit" class="btn btn-primary">Submit</button> </EditForm> @code { Employee employee { get; set; } = new Employee(); public void SubmitForm() { } }



Share with