Validation in .NET core
In this article, we will understand validation in ASP.NET Core MVC. Validation checks user input before sending it to the server. We can generally validate user input in two ways: client-side and server-side.
Client side Validation: Client-side validation occurs in the user’s browser before sending data to the server. This process typically uses JavaScript.
Advantages:
- Speed: Immediate feedback for users, enhancing user experience.
- Reduced Server Load: Fewer requests sent to the server since invalid data is caught early.
- User Engagement: Allows for dynamic and interactive forms.
Server Side Validation: it is type of Validation that occurs on the server after the data has been submitted. This is basically done using server side programming language C#
Advantages:
- Security: More secure since it cannot be easily bypassed by users.
- Comprehensive: Can access the database and perform complex checks (e.g., ensuring a username is unique).
- Consistent Logic: Centralizes validation logic, reducing redundancy across different clients.
In this article discussed about model validation and custom validation using asp .NET core mvc
In ASP .NET CORE MVC there are many ways to implement model validation using Data Annotation.
1. Data Annotations
This is the most common method for simple validation scenarios. It includes built-in attributes such as:
- [Required]: Ensures a property is not null or empty.
- [StringLength]: Limits the length of a string property.
- [Range]: Validates that a numeric value falls within a specified range.
- [EmailAddress]: Validates that a string is in a valid email format.
- [RegularExpression]: Validates a property against a specified regex pattern.
Create a Model
in this step we can create a model named usersmodel
using System.ComponentModel.DataAnnotations;
namespace Model_Validation.Models
{
public class UsersModel
{
[Required(ErrorMessage = "Username is required.")]
[StringLength(40, ErrorMessage = "Username may not be longer than 40 characters.")]
public string? Username { get; set; }
[Required(ErrorMessage = "Email is required.")]
[EmailAddress(ErrorMessage = "Invalid email format.")]
public string? Email { get; set; }
[Required(ErrorMessage = "Password is required.")]
[StringLength(100, MinimumLength = 6, ErrorMessage = "Password must be at least 6 characters long.")]
public string? Password { get; set; }
[Required(ErrorMessage = "First Name is required.")]
[StringLength(40, ErrorMessage = "First Name can't be longer than 40 characters.")]
public string? FirstName { get; set; }
[Required(ErrorMessage = "Last Name is required.")]
[StringLength(40, ErrorMessage = "Last Name can't be longer than 40 characters.")]
public string? LastName { get; set; }
[Required(ErrorMessage = "Date of Birth is required.")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime DateOfBirth { get; set; }
[Required(ErrorMessage = "Confirm Password is required.")]
[StringLength(100, MinimumLength = 6, ErrorMessage = "Confirm Password must match the Password.")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string? ConfirmPassword { get; set; }
}
}
Explanation of Fields
First Name:
Validation: Required and max length of 40 characters.
Last Name:
Validation: Required and max length of 40 characters.
Email:
Validation: Required to validate email format
Date of Birth:
Validation: Required and uses a date data type. The display format is set to yyyy-MM-dd.
Confirm Password:
Validation: Required, must match the Password field, and has a minimum length of 6 characters.
Create the Controller
In this step create a controller called UsersController that will handle registration logic
using Microsoft.AspNetCore.Mvc;
using Model_Validation.Models;
namespace Model_Validation.Controllers
{
public class UsersController : Controller
{
public IActionResult Index()
{
return View();
}
public IActionResult UsersRegister() {
return View();
}
[HttpPost]
public IActionResult Register(UsersModel model)
{
if (!ModelState.IsValid)
{
return View(model); // Return the same view with validation errors
}
// Logic to save user to database (omitted for brevity)
return RedirectToAction("Success");
}
public IActionResult Success()
{
return View();
}
}
}
Create a view:
we need to create a views for usersRegiter
@model UsersModel
@{
ViewData["Title"] = "UsersRegister";
}
<style>
body {
background-color: #f8f9fa;
}
h2 {
text-align: center;
margin-bottom: 20px;
}
.form-container {
max-width: 500px;
margin: auto;
padding: 20px;
background: white;
border-radius: 10px;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.1);
}
.form-group {
margin-bottom: 15px;
}
.btn-primary {
width: 100%;
}
.text-danger {
font-size: 0.875rem;
}
</style>
<div class="form-container">
<h2>Register</h2>
<form asp-action="Register" method="post">
<div class="form-group">
<label asp-for="Username"></label>
<input asp-for="Username" class="form-control" />
<span asp-validation-for="Username" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Email"></label>
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="FirstName"></label>
<input asp-for="FirstName" class="form-control" />
<span asp-validation-for="FirstName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="LastName"></label>
<input asp-for="LastName" class="form-control" />
<span asp-validation-for="LastName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="DateOfBirth"></label>
<input asp-for="DateOfBirth" type="date" class="form-control" />
<span asp-validation-for="DateOfBirth" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Password"></label>
<input asp-for="Password" type="password" class="form-control" />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ConfirmPassword"></label>
<input asp-for="ConfirmPassword" type="password" class="form-control" />
<span asp-validation-for="ConfirmPassword" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Register</button>
</form>
</div>
Create the Success View (Success.cshtml
)
<h1>Success</h1>
<h2>Registration Successful</h2>
<p>You have successfully registered!</p>
Custom Validation:
in this section we can demonstrate custom validation , to create a custom validation attribute we can apply different validation rules to all filed s we can extends AlphanumericAttribute to handle specific rules for each field.
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
namespace Model_Validation
{
public class CustomValidationAttribute : ValidationAttribute
{
private readonly string _fieldType;
public CustomValidationAttribute(string fieldType)
{
_fieldType = fieldType;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value != null)
{
var stringValue = value.ToString();
switch (_fieldType.ToLower())
{
case "username":
if (!Regex.IsMatch(stringValue, @"^[a-zA-Z0-9]*$"))
{
return new ValidationResult("Username must be alphanumeric.");
}
break;
case "email":
if (!new EmailAddressAttribute().IsValid(stringValue))
{
return new ValidationResult("Invalid email format.");
}
break;
case "password":
if (stringValue.Length < 6)
{
return new ValidationResult("Password must be at least 6 characters long.");
}
break;
case "name":
if (!Regex.IsMatch(stringValue, @"^[a-zA-Z]+$"))
{
return new ValidationResult("Name must contain only letters.");
}
break;
case "dateofbirth":
if (DateTime.TryParse(stringValue, out var date))
{
if (date > DateTime.Today)
{
return new ValidationResult("Date of Birth cannot be in the future.");
}
}
else
{
return new ValidationResult("Invalid Date of Birth format.");
}
break;
default:
return ValidationResult.Success;
}
}
return ValidationResult.Success;
}
}
}
Create a Action method
public IActionResult UsertsCustomvalidation()
{ return View(); }
[HttpPost]
public IActionResult RegisterCustom(UserModelCustom user)
{
//if (!ModelState.IsValid)
//{
// // If validation fails, return the same view with model to show errors
// return View("UsertsCustomvalidation");
//}
//return RedirectToAction("Success");
// second way either we can call using manual
ValidateModel(user);
if (!ModelState.IsValid)
{
return View("UsertsCustomvalidation"); // Return the same view with validation errors
}
return RedirectToAction("Success");
}
private void ValidateModel(UserModelCustom model)
{
var validationContext = new ValidationContext(model);
// Validate each property
foreach (var property in typeof(UserModelCustom).GetProperties())
{
var value = property.GetValue(model);
var attributes = property.GetCustomAttributes(typeof(ValidationAttribute), true);
foreach (ValidationAttribute attribute in attributes)
{
var result = attribute.GetValidationResult(value, validationContext);
if (result != ValidationResult.Success)
{
ModelState.AddModelError(property.Name, result.ErrorMessage);
}
}
}
}
Use the Attribute in Your Model
Make sure you’re using the CustomValidationAttribute
correctly in your UserModelCustom
. Here’s how it should look:
using System.ComponentModel.DataAnnotations;
namespace Model_Validation.Models
{
public class UserModelCustom
{
[Required(ErrorMessage = "Username is required.")]
[StringLength(50, ErrorMessage = "Username can't be longer than 50 characters.")]
[CustomValidation("username")]
public string Username { get; set; }
[Required(ErrorMessage = "Email is required.")]
[CustomValidation("email")]
public string Email { get; set; }
[Required(ErrorMessage = "Password is required.")]
[StringLength(100, MinimumLength = 6, ErrorMessage = "Password must be at least 6 characters long.")]
[CustomValidation("password")]
public string Password { get; set; }
[Required(ErrorMessage = "First Name is required.")]
[StringLength(50, ErrorMessage = "First Name can't be longer than 50 characters.")]
[CustomValidation("name")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Last Name is required.")]
[StringLength(50, ErrorMessage = "Last Name can't be longer than 50 characters.")]
[CustomValidation("name")]
public string LastName { get; set; }
[Required(ErrorMessage = "Date of Birth is required.")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[CustomValidation("dateofbirth")]
public DateTime DateOfBirth { get; set; }
[Required(ErrorMessage = "Confirm Password is required.")]
[StringLength(100, MinimumLength = 6, ErrorMessage = "Confirm Password must match the Password.")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
}
Create a view
@model UserModelCustom
@{
ViewData["Title"] = "UsertsCustomvalidation";
}
<style>
/* wwwroot/css/site.css */
body {
background-color: #f8f9fa;
}
h2 {
text-align: center;
margin-bottom: 20px;
}
.form-container {
max-width: 500px;
margin: auto;
padding: 20px;
background: white;
border-radius: 10px;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.1);
}
.form-group {
margin-bottom: 15px;
}
.btn-primary {
width: 100%;
}
.text-danger {
font-size: 0.875rem;
}
</style>
<h1>UsertsCustomvalidation</h1>
<div class="form-container">
<h2>Register</h2>
<form asp-action="RegisterCustom" method="post">
<div class="form-group">
<label asp-for="Username"></label>
<input asp-for="Username" class="form-control" />
<span asp-validation-for="Username" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Email"></label>
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="FirstName"></label>
<input asp-for="FirstName" class="form-control" />
<span asp-validation-for="FirstName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="LastName"></label>
<input asp-for="LastName" class="form-control" />
<span asp-validation-for="LastName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="DateOfBirth"></label>
<input asp-for="DateOfBirth" type="date" class="form-control" />
<span asp-validation-for="DateOfBirth" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Password"></label>
<input asp-for="Password" type="password" class="form-control" />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ConfirmPassword"></label>
<input asp-for="ConfirmPassword" type="password" class="form-control" />
<span asp-validation-for="ConfirmPassword" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Register</button>
</form>
</div>
Summary :
In summary, ASP.NET Core MVC offers flexible validation options through custom attributes, manual checks, and class-level validation, allowing you to effectively ensure data integrity. Utilizing libraries like FluentValidation can further streamline this process, enabling clear and maintainable validation logic. Ultimately, choosing the right approach enhances user experience and application reliability
for more details : apitpoint
featured pic : freepik.com