In this blog post, we will discuss how to use the Blazor EditForm for model validation. The EditForm component ships with the ASP.NET core package and allows us to easily validate user input and handle form submission events.
Here in the example, we will create a very simple form using the EditForm component to validate a user model in a Blazor Server application. If you are completely new to the Blazor application, I would highly recommend you to check the introductory post.
Blazor is a new framework provided by Microsoft to build interactive client-side web applications using C# programming language and Razor syntax on top of the .NET Core framework. The beauty of this framework is that the developer need not know any JavaScript and can leverage the existing .NET, .NET Core frameworks, and their associated NuGet packages to power the Blazor application. The developer can build a Blazor application that can run on the server or directly inside the client browsers.
Prerequisites
In this blog post, we are going to create a Blazor Server Application using the default template provided by Visual Studio 2019. At the time of writing the current version of .NET Core is 5.0, but the same is applicable on lower versions also:
- Visual Studio 2019 (v16.8) – Community Edition [download here]
- .NET Core SDK 5.0 [download here]
The Blazor EditForm Component – Overview
The EditForm component provides a few important attributes and event handlers that the user can use to perform validation with ease. Below are a few important points to note before using EditForm.
- The form uses Data Annotation for validation.
- The form exposes a Model attribute that accepts a model class to validate.
- The ValidationSummary component is used to summarize and display validation messages.
- The EditForm creates an EditContext that tracks the fields changes and validation message.
- Either EditContext or Model attribute should be assigned for validation, they cannot be used together. Assignment of both these values will generate a runtime error.
- The EditForm provides three important event handlers for users, each of these passes EditContext as a parameter.
- OnValidSubmit: This event handler is invoked whenever the form is submitted and the EditContext is found to be valid.
- OnInvalidSubmit: This event handler is invoked whenever the form is submitted and the EditContext is found to be invalid.
- OnSubmit: This method is invoked whenever the form is submitted and without considering EditContext validation, it is left to the user to explicitly validate the EditContext and is mostly used when you have a custom validation logic.
Use Case Scenario – Validating User Model
Let us take a simple use case scenario that we have a model representing a User and we need to have a UI component that will accept a new User using the Blazor EditForm component.
Following are the properties and the constraints that are defined in the User model.
- Id: This property represents the user id and will be auto-assigned when the User model is saved in the database.
- FirstName: This is not a mandatory field. The user can choose not to provide the value.
- LastName: This is a mandatory field and must contain a maximum of 20 and a minimum of 3 characters.
- DateOfBirth: This is a mandatory field and the user age must not be less than 1-Jan-2000 and greater than 31-Dec-2019.
- Email: This is a mandatory field and must contain a valid email id.
Now let us implement this scenario using the Blazor Server application, the same can be done using Blazor WebAssembly as well as Blazor PWA.
Use case scenario implementation:
1. Create the Blazor Server Application
First, we are going to create a Blazor Server application in Visual Studio 2019. I have named the project “BlazorEditFormSample“. [Please check this short video on how to create a Blazor Server application]
2. Add a new class User inside the Data folder
namespace BlazorEditFormSample.Data { public class User { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public DateTime DateOfBirth { get; set; } public string Email { get; set; } } }
3. Modify the User class to add Validation and Error Messages as per use case requirement.
In order to add data annotation, we need the following namespace: using System.ComponentModel.DataAnnotations in our User class.
using System; using System.ComponentModel.DataAnnotations; namespace BlazorEditFormSample.Data { public class User { public int Id { get; set; } public string FirstName { get; set; } [Required(ErrorMessage = "Last Name is required")] [StringLength(20, MinimumLength = 3, ErrorMessage = "Last Name cannot have less than 3 characters and more than 20 characters in length")] public string LastName { get; set; } [Required] [Range(typeof(DateTime), "1-1-2000", "12-31-2019", ErrorMessage = "Date of Birth must between 1-Jan-2000 and 31-Dec-2019")] public DateTime DateOfBirth { get; set; } [Required(ErrorMessage = "Email is required")] [DataType(DataType.EmailAddress)] [EmailAddress] public string Email { get; set; } } }
4.1 Implementation – Using the EditForm Model attribute
The first way to implement it is by using the Model attribute of the Blazor EditForm component, so we are going to implement the requirement using the same and see how we can do it.
Please replace the code of index.razor with the following code.
@page "/" @using BlazorEditFormSample.Data <div class="container"> <EditForm Model="@NewUser" OnValidSubmit="@HandleValidSubmit" OnInvalidSubmit="HandleInvalidSubmit"> <DataAnnotationsValidator /> <div class="row"> <div class="col-md-8"> <div class="row" style="margin-top:10px"> <div class="col-md-12"> <label for="firstName">First Name #</label> <input type="text" class="form-control" id="firstName" @bind-value="@NewUser.FirstName" placeholder="enter first name..." /> <ValidationMessage For="@(()=>NewUser.FirstName)" /> </div> </div> <div class="row" style="margin-top:10px"> <div class="col-md-12"> <label for="lastName">Last Name #</label> <input type="text" class="form-control" id="lastName" @bind-value="@NewUser.LastName" placeholder="enter last name..." /> <ValidationMessage For="@(()=>NewUser.LastName)" /> </div> </div> <div class="row" style="margin-top:10px"> <div class="col-md-12"> <label for="lastName">Date of Birth #</label> <input type="text" class="form-control" id="department" @bind-value="@NewUser.DateOfBirth" /> <ValidationMessage For="@(()=>NewUser.DateOfBirth)" /> </div> </div> <div class="row" style="margin-top:10px"> <div class="col-md-12"> <label for="email">Email Id #</label> <input type="text" class="form-control" id="email" @bind-value="@NewUser.Email" placeholder="email..." /> <ValidationMessage For="@(()=>NewUser.Email)" /> </div> </div> <button type="submit" class="btn btn-info" Style="margin-top:10px">Add user</button> </div> @if (displayValidationErrorMessages) { <div class="col-md-4" style="margin-top:10px"> <label>Validation Messages: </label> <ValidationSummary /> </div> } </div> </EditForm> @if (displayUserAddedToDB) { <div class="row bg-success text-white" style="margin-top:10px; height:40px"> <label class="p-2">User added to database... </label> </div> } </div> @code { User NewUser = new User(); bool displayValidationErrorMessages = false; bool displayUserAddedToDB = false; private void HandleValidSubmit(EditContext context) { displayValidationErrorMessages = false; displayUserAddedToDB = true; } private void HandleInvalidSubmit(EditContext context) { displayValidationErrorMessages = true; displayUserAddedToDB = false; } }
Summary of the code added to index.razor
- We have created a new User object called “NewUser” in the code section, this property is used to bind the Model attribute of the EditForm.
- HandleValidSubmit(EditContext context): Handler is added and is attached as a callback to the OnValidSubmit event. It is invoked when the user clicks on the “Add user” button and the Model is in a valid state. Here we are just updating boolean properties to display messages on the UI.
- HandleInvalidSubmit(EditContext context): Handler is added and is attached as a callback to the OnInvalidSubmit event. It is invoked when the user clicks on the “Add user” button and the Model is in an invalid state. Here again, we are just updating boolean properties to display messages on the UI.
- DataAnnotationsValidator component is added inside the EditForm component in order to add the validation support.
- ValidationMessage component is added after every input type to be validated in order to display any validation failure message.
- Added a message “User added to database” just to mimic validation has passed and some processing has happened.
Output of the application:
4.2 Implementation – Using EditForm EditContext attribute
The second way to implement it using the EditContext attribute of the Blazor EditForm component. For this, we need an EditContext type that refers to the User object and assigns the same to the attribute.
Please replace the code of the index.razor with the following code.
@page "/" @using BlazorEditFormSample.Data <div class="container bg-light"> <EditForm EditContext="@context" OnSubmit="@SubmitEventHandler"> <DataAnnotationsValidator /> <div class="row"> <div class="col-md-8"> <div class="row" style="margin-top:10px"> <div class="col-md-12"> <label for="firstName">First Name #</label> <input type="text" class="form-control" id="firstName" @bind-value="@NewUser.FirstName" placeholder="enter first name..." /> <ValidationMessage For="@(()=>NewUser.FirstName)" /> </div> </div> <div class="row" style="margin-top:10px"> <div class="col-md-12"> <label for="lastName">Last Name #</label> <input type="text" class="form-control" id="lastName" @bind-value="@NewUser.LastName" placeholder="enter last name..." /> <ValidationMessage For="@(()=>NewUser.LastName)" /> </div> </div> <div class="row" style="margin-top:10px"> <div class="col-md-12"> <label for="lastName">Date of Birth #</label> <input type="text" class="form-control" id="department" @bind-value="@NewUser.DateOfBirth" /> <ValidationMessage For="@(()=>NewUser.DateOfBirth)" /> </div> </div> <div class="row" style="margin-top:10px"> <div class="col-md-12"> <label for="email">Email Id #</label> <input type="text" class="form-control" id="email" @bind-value="@NewUser.Email" placeholder="email..." /> <ValidationMessage For="@(()=>NewUser.Email)" /> </div> </div> <button type="submit" class="btn btn-info" Style="margin-top:10px">Add user</button> </div> @if (displayValidationErrorMessages) { <div class="col-md-4" style="margin-top:10px"> <label>Validation Messages: </label> <ValidationSummary /> </div> } </div> </EditForm> @if (displayUserAddedToDB) { <div class="row bg-success text-white" style="margin-top:10px; height:40px"> <label class="p-2">User added to database... </label> </div> } </div> @code { User NewUser = new User(); EditContext context; protected override Task OnInitializedAsync() { context = new EditContext(NewUser); return base.OnInitializedAsync(); } bool displayValidationErrorMessages = false; bool displayUserAddedToDB = false; private void SubmitEventHandler(EditContext context) { if(context.Validate()) { displayValidationErrorMessages = false; displayUserAddedToDB = true; } else { displayValidationErrorMessages = true; displayUserAddedToDB = false; } } }
Summary of the code added to index.razor
- We have created a new User object called “NewUser” in the code section, this property will be passed to the constructor of the EditContext class.
- Next, we have created an object of EditContext class and initialize and assign the same to the instance of the User object in the OnInitializedAsync(). After that, the reference of this object is pointed to the EditContext attribute of the EditForm.
- SubmitEventHandler(EditContext context): Handler is added and is attached as a call back to the OnSubmit() event handler of the EditForm. The handler is invoked every time the user clicks on the “Add user” button. The code for checking if the model is valid is also handled in this method by calling the context.Validate().
- Added a message “User added to database” just to mimic validation has passed and some processing has happened.
Output of the application:
Conclusion
The Blazor EditForm component along with the DataAnnotationsValidator class provides a very convenient way to implement model validation in a Blazor application. The user can also define their own custom validation attribute or a validator as per their need. The details can be found on the Microsoft Doc.
I hope you find the post on using EditForm in a Blazor application helpful. Thanks for visiting. Cheers!!!
[Further Readings: How to add a new profile in Windows Terminal | How to easily Customize Global Settings in Windows Terminal | How to add Git Bash to Windows Terminal Application | How to customize Windows Terminal Application | How to customize Windows Terminal Key Bindings | How to Install Windows Terminal in Windows 10 | Important Debugging Shortcuts of Visual Studio 2019 | How to publish a Blazor Server Application to IIS | Top 7 Visual Studio 2019 extensions for Web Projects | The difference in Blazor Server and WebAssembly Application | Exploring Blazor WebAssembly App Project Structure | Top 10 Productivity Tips and Tricks in Visual Studio 2019 ]