Mastering User Input Validation - A Guide To Implementing Validations In Blazor

Introduction

Validating user input is an essential part of building web applications. Blazor provides several built-in validation features that can help ensure user input is accurate and meets specific criteria. By using these validation features, we can design more reliable applications. By the end of this article, you will better understand how to use these validation features effectively to create more efficient applications.

This article will explore how to implement Blazor validations with examples. To implement client-side validations that help to ensure the data entered into forms is accurate.

To begin with, let me lay down the steps:

  • Step 1 - Create a model class and decorate its properties with data annotations.
  • Step 2 - Add a Blazor component
    1. Add EditForm in a component
    2. Specify <DataAnnotationsValidator/> and <ValidationSummary/> under editform
    3. Add a method to handle an event for the OnValidSubmit property
    4. Adding UI elements and binding model-class's properties to each element
  • Bonus - We will also create our own custom validations to define our own password policy.

Step 1. Create a model class and decorate its properties with data annotations.

We will use data annotation to validate the behavior of the UI property. These annotations can be applied to the properties of a model class which we will bind in UI.

Create a class Person under the Pages folder and add six properties Name, Age, Email, ConfirmEmail, Password, and Address.

using System.ComponentModel.DataAnnotations;

namespace BlazingValidations.Pages
{
    public class Person
    {
        [Required]
        public string Name { get; set; }

        [Range(21, 35, ErrorMessage = "Please enter a valid age!")]
        public int Age { get; set; }

        [Required(ErrorMessage = "Please enter your email!")]
        [EmailAddress(ErrorMessage = "Please enter a valid email address!")]
        [RegularExpression(@"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$", ErrorMessage = "Please enter a valid email address format!")]
        public string Email { get; set; }

        [Compare("Email", ErrorMessage = "Confirm Email must match!")]
        public string ConfirmEmail { get; set; }

        [Required(ErrorMessage = "Please enter your password!")]
        public string Password { get; set; }


        [Required(ErrorMessage = "Please enter your address.")]
        [StringLength(15, MinimumLength = 10, ErrorMessage = "Address must be between 10 and 15 characters!")]
        public string Address { get; set; }
    }
}

Listing 1: class Person

Following is the list of validation attributes that we've used in listing 1:

  • [Required]: Specifies that a property is required and must not be empty or null.
    • It is applied on the Name, Email, Password, and Address properties. An appropriate error message will be displayed if the user submits the form without entering any of these fields.
    • Notice for Name, I've not specified any error message, so it generates the default error message "The Name field is required". Check output image 2 below.
  • [RegularExpression]: Specifies a regular expression that a property must match.
    • RegularExpression attribute specifies that the Email property must contain a valid email address format. e.g., [email protected]. If the user enters an invalid email address, an error message "Please enter your email!" will be displayed.
  • [Range]: Specifies the minimum and maximum value of a property.
    • The Range is applied to Age to ensure a person is between 21 and 35. If the user enters an Age outside of these bounds, then an error message "Please enter a valid age!" will be displayed.
  • [Compare]: Compares the values of two properties.
    • I am using Compare on the ConfirmEmail property to ensure both Email and ConfirmEmail are the same. If ConfirmEmail doesn't match with Email, an error message "ConfirmEmail must match!" will be displayed.
  • [StringLength]: Specifies the minimum and maximum length of a string property.
    • It has been applied on the Address to ensure the address is at least 10 characters long and not larger than 15 characters. If the user enters an Address that is < 10 characters or > 15 characters, then an error message "Address must be between 10 and 15 characters!" will be displayed.

Note: We must import the "System.ComponentModel.DataAnnotations" namespace to our project.

Step 2. Add a Blazor component

Right-click on the Pages folder and select the new razor component. This will open up the "Add New Item" dialog box, name the component "BlazorValidations," and click on the "Add" button.


Image 1: Add new razor component

1. Add EditForm in a component

@page "/BlazorValidations"
<h3>Blazor Validations</h3>

<EditForm Model="@person">
    <button type="submit">Submit</button>
</EditForm>

@code {
}

Listing 2: BlazorValidations.razor

2. Specify <DataAnnotationsValidator/> and <ValidationSummary/> under editform

<DataAnnotationsValidator />
<ValidationSummary />

Listing 3: DataAnnotationsValidator, ValidationSummary tags

3. Add a method to handle an event for the OnValidSubmit property

@code {
    private async Task AddPerson()
    {
        //Your task
    }
}

Listing 4: Event-handler for OnValidSubmit

4. Adding fields and bind Person object's properties in UI

@page "/BlazorValidations"
<h3>Blazor Validations</h3>

<EditForm Model="@person" OnValidSubmit="@AddPerson">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <div>
        <InputText class="form-control" @bind-Value="@person.Name" placeholder="Your name.." />
    </div>

    <div>
        <InputNumber class="form-control" @bind-Value="@person.Age" placeholder="Your age.." />
    </div>

    <div>
        <InputText class="form-control" @bind-Value="@person.Email" placeholder="Your email.." />
    </div>

    <div>
        <InputText class="form-control" @bind-Value="@person.ConfirmEmail" placeholder="Confirm email.." />
    </div>

    <div>
        <InputText class="form-control" @bind-Value="@person.Password" placeholder="Your password.." />
    </div>

    <div>
        <InputTextArea class="form-control" @bind-Value="@person.Address" placeholder="Your address.." />
    </div>

    <button type="submit">Submit</button>
</EditForm>

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

    private async Task AddPerson()
    {
        // Perform
    }
}

Listing 5: BlazorValidations.razor

In the above code, we have added an EditForm component and bound it to the Person model. We have also added a DataAnnotationsValidator and ValidationSummary components to validate the form fields.

We have created six form fields: Name, Age, Email, ConfirmEmail, Password, and Address.

The input fields are bound to the corresponding properties of the person model using the @bind-Value directive.

When the user submits the form, the OnValidSubmit event is triggered, and the AddPerson method is called. If the form is valid, we can perform our desired action, such as submitting the form to a server. The validation messages will be displayed in a summary if the form is invalid, like the following image.

Mastering User Input Validation: A Guide to Implementing Validations in Blazor
Image 2: Error messages in validation summary

Placing error messages next to the error field.

You can also specify error messages next to the corresponding field using ValidationMessage.

<div>
  <InputText class="form-control" @bind-Value="@person.Name" placeholder="Your name.." />
  <ValidationMessage For="@(() => person.Name)" />
</div>
<div>
  <InputNumber class="form-control" @bind-Value="@person.Age" placeholder="Your age.." />
  <ValidationMessage For="@(() => person.Age)" />
</div>
<div>
  <InputText class="form-control" @bind-Value="@person.Email" placeholder="Your email.." />
  <ValidationMessage For="@(() => person.Email)" />
</div>
<div>
  <InputText class="form-control" @bind-Value="@person.ConfirmEmail" placeholder="Confirm email.." />
  <ValidationMessage For="@(() => person.ConfirmEmail)" />
</div>
<div>
  <InputText class="form-control" @bind-Value="@person.Password" placeholder="Your password.." />
  <ValidationMessage For="@(() => person.Password)" />
</div>
<div>
  <InputTextArea class="form-control" @bind-Value="@person.Address" placeholder="Your address.." />
  <ValidationMessage For="@(() => person.Address)" />
</div>

Listing 6: ValidationMessage

In the above listing 6, the ValidationMessage components are bound to the corresponding properties of the Person model using a lambda expression. The output would look like this.

Mastering User Input Validation: A Guide to Implementing Validations in Blazor
Image 3: Error messages in validation message

Custom Validations

The above example demonstrates how to use the built-in validation attributes. We can also create and apply our custom validation attributes to the model properties. This allows us to define custom validation rules and messages for our forms.

To create a custom validation attribute, we can create a new class and derive it from the ValidationAttribute base class, then override the IsValid method. Here is an example to define a password policy.

using System.ComponentModel.DataAnnotations;

namespace BlazingValidations.Pages
{
    public class PasswordValidation : ValidationAttribute
    {
        private readonly int _minLength;
        private readonly int _maxLength;
        private readonly bool _requireDigit;
        private readonly bool _requireLowercase;
        private readonly bool _requireUppercase;
        private readonly bool _requireNonAlphanumeric;

        public PasswordValidation(int minLength, int maxLength, bool requireDigit, bool requireLowercase, bool requireUppercase, bool requireNonAlphanumeric)
        {
            _minLength = minLength;
            _maxLength = maxLength;
            _requireDigit = requireDigit;
            _requireLowercase = requireLowercase;
            _requireUppercase = requireUppercase;
            _requireNonAlphanumeric = requireNonAlphanumeric;
        }

        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            string password = value as string;

            if (password.Length < _minLength || password.Length > _maxLength)
                return new ValidationResult($"The password must be between {_minLength} and {_maxLength} characters long.");

            if (_requireDigit && !password.Any(char.IsDigit))
                return new ValidationResult("The password must contain at least one digit.");

            if (_requireLowercase && !password.Any(char.IsLower))
                return new ValidationResult("The password must contain at least one lowercase letter.");

            if (_requireUppercase && !password.Any(char.IsUpper))
                return new ValidationResult("The password must contain at least one uppercase letter.");

            if (_requireNonAlphanumeric && !password.Any(c => !char.IsLetterOrDigit(c)))
                return new ValidationResult("The password must contain at least one non-alphanumeric character.");

            return ValidationResult.Success;
        }
    }
}

Listing 7: PasswordValidation for custom validations

In this example, we've created a PasswordValidation class that takes several parameters in its constructor to specify the password validation rules. These rules include the minimum and maximum length of the password, whether the password requires at least one digit, a lowercase letter, an uppercase letter, and a non-alphanumeric character.

The IsValid method then checks whether the password meets these validation rules. If it doesn't, a ValidationResult object is returned with an appropriate error message.

To use this custom validation attribute in your model class Person, you can apply it to your password property like this:

[Required]
[PasswordValidation(8, 20, true, true, true, true, ErrorMessage = "Invalid password format!")]
public string Password { get; set; }

Listing 8: Applying custom validation "PasswordValidation" on model property "Password"

In listing 8, we've applied the PasswordValidation attribute to our password property, specifying the minimum length of 8 characters and a maximum length of 20 characters, requiring at least one digit, a lowercase letter, an uppercase letter, and a non-alphanumeric character. If the password fails to meet these requirements, a specified error message will be displayed.

By creating custom validation attributes like this, you can easily enforce complex validation rules on your form data and ensure it meets your application's requirements.

Conclusion

We learned today how to implement validations in Blazor and how to create your own custom validations. With this, you can create more efficient and reliable applications that provide a better user experience. Whether you are new to Blazor or an experienced developer, understanding and implementing validations is crucial to building robust web applications. Therefore, it is recommended to take advantage of Blazor's validation features to ensure that user input is validated correctly and improve the overall quality of the application.


Similar Articles