C# tutorials > Frameworks and Libraries > ASP.NET Core > Model Binding and Validation (data annotations, custom validation)
Model Binding and Validation (Data Annotations, Custom Validation) in ASP.NET Core
This tutorial explores Model Binding and Validation in ASP.NET Core, focusing on Data Annotations and Custom Validation. Model Binding automatically maps incoming HTTP request data to the properties of your model. Validation ensures that the bound data meets specific requirements before being processed. We'll cover how to use Data Annotations for common validation scenarios and how to create custom validation attributes for more complex requirements.
Introduction to Model Binding
Model Binding is the process of converting incoming HTTP request data (e.g., from form fields, query strings, or route parameters) into .NET objects that your controller actions can work with. ASP.NET Core handles this automatically, simplifying data access within your application.
Introduction to Validation
Validation ensures that the data received through Model Binding is in a valid state before being used by your application. This helps prevent errors, improves data quality, and enhances security. Validation can be implemented using Data Annotations or custom validation logic.
Data Annotations: A Simple Example
This code snippet demonstrates basic Data Annotations. [Required]
ensures the Name
property is not empty. [StringLength]
limits the length of the Name
. [Range]
specifies the acceptable range for the Price
. [EmailAddress]
validates that the SupportEmail
is a valid email format. The ErrorMessage
properties provide user-friendly feedback when validation fails.
public class Product
{
[Required(ErrorMessage = "Product Name is required")]
[StringLength(100, MinimumLength = 3, ErrorMessage = "Product Name must be between 3 and 100 characters")]
public string Name { get; set; }
[Range(0.01, 1000, ErrorMessage = "Price must be between 0.01 and 1000")]
public decimal Price { get; set; }
[EmailAddress(ErrorMessage = "Invalid Email Address")]
public string SupportEmail { get; set; }
}
Using Data Annotations in a Controller
In your controller action, check the ModelState.IsValid
property. If it's true
, the model is valid and you can proceed with your logic (e.g., saving the product to a database). If it's false
, the ModelState
contains validation errors that you should display in your view.
[HttpPost]
public IActionResult Create(Product product)
{
if (ModelState.IsValid)
{
// Save the product to the database
return RedirectToAction("Index");
}
// If validation fails, return the view with validation errors
return View(product);
}
Displaying Validation Errors in a View
In your Razor view, use the asp-validation-summary
tag helper to display a summary of all validation errors. Use the asp-validation-for
tag helper next to each input field to display specific error messages for that field. The text-danger
CSS class (often from Bootstrap) styles the errors in red.
@model Product
<form asp-action="Create" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Price" class="control-label"></label>
<input asp-for="Price" class="form-control" />
<span asp-validation-for="Price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
Creating Custom Validation Attributes
To create a custom validation attribute, inherit from the ValidationAttribute
class. Override the IsValid
method, which contains your validation logic. The value
parameter is the value being validated, and the validationContext
provides access to the model and other context information. Return a ValidationResult
to indicate success or failure.
using System.ComponentModel.DataAnnotations;
public class ValidAgeAttribute : ValidationAttribute
{
private readonly int _minAge;
public ValidAgeAttribute(int minAge)
{
_minAge = minAge;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value != null)
{
DateTime birthDate = (DateTime)value;
int age = DateTime.Now.Year - birthDate.Year;
if (age < _minAge)
{
return new ValidationResult($"Age must be at least {_minAge} years.");
}
}
return ValidationResult.Success;
}
}
Using the Custom Validation Attribute
Apply your custom validation attribute to a property just like any other Data Annotation. Pass any necessary parameters to the attribute's constructor. In this example, we require that the BirthDate
results in an age of at least 18 years.
public class Person
{
[Required]
public string Name { get; set; }
[ValidAge(18, ErrorMessage = "You must be at least 18 years old")]
public DateTime BirthDate { get; set; }
}
Concepts Behind the Snippet
The core concepts are: declarative validation through attributes, leveraging the ModelState
to track validation status, and the ability to extend validation with custom logic when the built-in attributes are insufficient.
Real-Life Use Case Section
Imagine an e-commerce application where users register and provide their shipping addresses. Model Binding and Validation can ensure that the address fields are correctly populated (e.g., zip codes have the correct format, required fields are not empty) before processing the order. Similarly, in a banking application, ensuring valid account numbers, amounts, and transaction details is crucial for financial integrity.
Best Practices
Interview Tip
Be prepared to explain the difference between Data Annotations and custom validation, and when you might choose one over the other. Also, be ready to discuss the role of ModelState.IsValid
in ASP.NET Core controllers and how it ties into the validation process. Being able to discuss client-side vs. server-side validation is also key.
When to Use Them
Use Data Annotations for simple, common validation scenarios like required fields, string length constraints, and range checks. Use custom validation attributes when you need to implement more complex validation logic that cannot be easily expressed using Data Annotations alone.
Memory Footprint
Data Annotations themselves have a minimal memory footprint. The memory impact comes from storing the validated data and the validation error messages. Custom validation attributes have a slightly larger footprint due to the additional code they execute, but this is typically negligible unless you have a very large number of custom attributes or the validation logic is computationally expensive.
Alternatives
Alternatives to Data Annotations include:
Pros of Data Annotations
Cons of Data Annotations
FAQ
-
What happens if ModelState.IsValid is false?
If
ModelState.IsValid
isfalse
, it means that the model has failed validation. TheModelState
property in your controller contains a collection of errors that you can display to the user, typically in your view, to indicate which fields have invalid data. -
Can I use Data Annotations and Custom Validation together?
Yes, you can absolutely use Data Annotations and Custom Validation attributes together within the same model. This allows you to leverage the simplicity of Data Annotations for common validation tasks while using custom attributes for more specific or complex validation requirements.
-
How do I perform client-side validation with Data Annotations?
ASP.NET Core automatically generates client-side validation scripts based on your Data Annotations. Ensure you have included the necessary JavaScript libraries (e.g., jQuery Validation and jQuery Validation Unobtrusive) in your view. These scripts will perform validation in the browser before the form is submitted to the server.