How do I enable validation without using the DataAnnotationValidator?

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()     {       } } View Sample in GitHub

What is the purpose of a display name in built-in form components?

The DisplayName property, which is set for built-in form components, help maintain an alternate name. When the component’s input value is incorrect due to form validation, this alternate name is displayed in the error message. The DisplayName property is supported by the following built-in components. Please refer to the code example below. [Index.razor] View Sample in GitHub

How to add custom validation in Blazor using custom validation attribute?

By default, the System.ComponentModel.Annotations library provides different validation attributes. However, to add a new or custom validation, users can create a custom validation attribute and apply it to their model class. To create an attribute: Create a Blazor Server Application with latest .NET support. Install the System.ComponentModel.Annotations NuGet package to perform custom validation in Created project. Create a new folder named Models in the main application and add the following *.cs files –EmployeeDetails, OrganizationValidationAttribute to it as shown below. Add a model EmployeeDetails class name in the EmployeeDetails.csfile. using System.ComponentModel.DataAnnotations;namespace BlazorServerApp.Models{ public class EmployeeDetails { [Required] public string? Name { get; set; } [Required] public string? Organization { get; set; } }} Create a new OrganizationValidationAttribute.cs file and then the OrganizationValidationAttribute class, which is derived from ValidationAttribute. The ValidationAttribute from System.ComponentModel.Annotations acts as the base class for validation. [OrganizationValidationAttribute.cs] using System.ComponentModel.DataAnnotations; namespace BlazorServerApp.Models{ public class OrganizationValidationAttribute : ValidationAttribute { public string? ValidOrganizationName { get; set; } protected override ValidationResult? IsValid ( object? value, ValidationContext? validationContext ) { string fieldValue = value!.ToString()!.ToLower(); if (fieldValue.Equals(ValidOrganizationName?.ToLower())) return null; return new ValidationResult(ErrorMessage, new[] { validationContext?.MemberName }.Cast()); } }} The ValidOrganizationName property can be set from the model EmployeeDetails class. Following that, override the IsValid method, which takes two parameters, value and validationContext. The value parameter contains the value that the user entered in the Organization field. The validationContext parameter is used to explain the context in which validation is performed. If the value is equal to the ValidOrganizationName, no errors will be thrown; otherwise, an error message returns. Add the following custom validation attribute to the Organization property. using System.ComponentModel.DataAnnotations;namespace BlazorServerApp.Models{ public class EmployeeDetails { [Required] public string? Name { get; set; } //Here OrganizationValidation is a Customvalidation Attribute [Required] [OrganizationValidation(ErrorMessage = “Invalid customer log-in.”, ValidOrganizationName = “Syncfusion”)] public string? Organization { get; set; } }} Moving back to the Blazor Server application, add the following code to the Index.razor page to render a form with validation settings. [Index.razor] @page “/” @using BlazorServerApp.Models <EditForm Model=”_product” OnValidSubmit=”Submit” style=”width:600px;”><DataAnnotationsValidator /> <ValidationSummary/> <div class=”form-group row”> <label for=”name” class=”col-md-2 col-form-label”>Name: <label for=”name” class=”col-md-2 col-form-label”>Name: <div class=”col-md-10″> <InputText id=”name” class=”form-control” @bind-Value=”_product.Name” /> <ValidationMessage For=”@(() => _product.Name)” /> </div> </div> <div class=”form-group row”> <label for=”organization” class=”col-md-2 col-form-label”>Organization: <div class=”col-md-10″> <InputText id=”supplier” class=”form-control” @bind-Value=”_product.Organization” /> <ValidationMessage For=”@(() => _product.Organization)” /> </div> </div> <div class=”row”> <div class=”col-md-12 text-right”> <button type=”submit” class=”btn btn-success”>Submit</button> </div> </div></EditForm>@code{private EmployeeDetails _product = new EmployeeDetails();public void Submit () => Console.WriteLine($”{_product.Name}, {_product.Organization}”);} The following outputs will be seen after submitting the form.  View Sample in GitHub 

How do I validate a nested complex model in Blazor?

The built-in DataAnnotationsValidator allows you to validate form input using data annotations,  but it only validates top-level properties bound to the form and not child or complex type properties. To validate the nested complex  model, replace the DataAnnotationsValidator with the ObjectGraphDataAnnotationsValidator, which validates the entire object, including child and complex type properties in the form. Install the following package via Package Manager Console in order to use the ObjectGraphDataAnnotationsValidator. PM> Install-Package Microsoft.AspNetCore.Components.DataAnnotations.Validation -Version 3.2.0-rc1.20223.4 Create a new Folder named StudentDetails in the main application and add the class named Student.cs to the StudentDetails folder. In Student.cs file, create two model classes -Student and PersonalDetails. Here, add ValidateComplexType belonging to the ObjectGraphDataAnnotationsValidator above the complex type declaration. using System.ComponentModel.DataAnnotations;namespace Validating_Complex_Model_in_Blazor.StudentDetails{ public class Student { public Student () { Details = new PersonalDetails(); } [Required] public string Name { get; set; } [Required] public string Department { get; set; } [ValidateComplexType] public PersonalDetails Details { get; set; } } public class PersonalDetails { [Required] public int Age { get; set; } [Required] public string? Address { get; set; } }} Create an Index.razor page with the EditForm and Input components shown in the code sample below. Set the Model property of the EditForm component to the Student class instance. Additionally, the ObjectGraphDataAnnotationsValidator and ValidationSummary tags are used for validation and the display of validation summary, respectively. @page “/”@using Validating_Complex_Model_in_Blazor.StudentDetails<EditForm Model=”@_student” OnValidSubmit=”@HandleValidSubmit” OnInvalidSubmit=”@HandleInvalidSubmit”>    <ObjectGraphDataAnnotationsValidator />     <ValidationSummary />     <div class=”form-group”>         <label for=”name”>Name: </label>         <InputText Id=”name” Class=”form-control” @bind-Value=”@_student.Name”></InputText>         <ValidationMessage For=”@(() => _student.Name)” />     </div>     <div class=”form-group”>         <label for=”department”>Department: </label>         <InputText Id=”department” Class=”form-control” @bind-Value=”@_student.Department”></InputText>         <ValidationMessage For=”@(() => _student.Department)” />     </div>     <div class=”form-group”>         <label for=”address”>Address: </label>         <InputTextArea Id=”address” Class=”form-control” @bind-Value=”@_student.Details.Address”></InputTextArea>         <ValidationMessage For=”@(() => _student.Details.Address)” />     </div>     <button type=”submit”>Submit</button> </EditForm>   @code {     public string StatusMessage;     public Student _student = new Student();       public void HandleValidSubmit()     {         StatusMessage = “It’s a valid submission.”;     }       public void HandleInvalidSubmit()     {         StatusMessage = “It’s an invalid submission. Please see the error message(s) listed below.”;     } }   View Sample in GitHub

What is an EditContext and how do I define and use it in a form?

The EditContext of the form stores information about the editing process, such as which fields have been changed and which validation messages are currently displayed. To manually pass the EditContext to the EditForm, follow the steps below. Create a new Customer.cs file and model Customer class. public class Customer {     [Required]     public string Name { get; set; }       [Required]     [StringLength(4, ErrorMessage = “The organization code must be less than 5 characters in length.”)]     public string OrganizationCode { get; set; } } Insert an EditForm component into the Index.razor page. Then, make instances of the Customer class and the EditContext, and assign the Customer class instance to the EditContext instance. Finally, bind the EditContext instance to the EditContext property in the EditForm component. @page “/”   <EditForm EditContext=”@editContext”>     <DataAnnotationsValidator />     <ValidationSummary />   </EditForm>   @code {     private Customer _customer = new Customer();     private EditContext editContext;       protected override void OnInitialized()     {         editContext = new(_customer);     } } As the EditContext stores all the form information, it can be used to validate the form components. Add the Razor code as given below with input  texts and a button. When a form is submitted, the Validate() method is invoked to perform validation. @page “/”   <EditForm EditContext=”@editContext”>     <DataAnnotationsValidator />     <ValidationSummary />     <div class=”form-group”>         <label for=”name”>Name:</>         <InputText id=”name” @bind-Value=”_customer.Name” />         <ValidationMessage For=”=”@(() => _customer.Name)” />     </div>        <div class=”form-group”>         <label for=”organizationCode”>Organization Code:</>         <InputText id=”organizationCode” class=”form-control” @bind-Value=”_customer.OrganizationCode”/>         <ValidationMessage For=”=”@(() => _customer.OrganizationCode)” />        </div>     <div style=”margin-top: 10px;”>         <button type=”submit” class=”btn btn-primary” @onclick=”Submit”>Submit</button>        </div> </EditForm> View Sample in GitHub