Implementing Validation in ASP.NET Core MVC

This tutorial explores how to implement robust data validation in your ASP.NET Core MVC applications. Proper validation ensures data integrity and provides a better user experience by giving immediate feedback on input errors.

Client-Side vs. Server-Side Validation

Validation in ASP.NET Core MVC can be performed on both the client-side (in the browser) and the server-side (on the web server). Both are crucial for a complete validation strategy:

  • Client-Side Validation: Provides immediate feedback to the user as they fill out a form, improving usability and reducing unnecessary server requests.
  • Server-Side Validation: Is the ultimate safeguard. It ensures data integrity even if client-side validation is bypassed or disabled.

Using Data Annotations

The most common and recommended way to implement validation in ASP.NET Core is by using data annotations from the System.ComponentModel.DataAnnotations namespace. These attributes are applied directly to your model properties.

Common Validation Attributes:

  • [Required]: Marks a property as mandatory.
  • [StringLength(int maxLength, int minLength = 0)]: Validates the length of a string.
  • [RegularExpression(string pattern)]: Validates a string against a regular expression.
  • [EmailAddress]: Validates that a string is a valid email format.
  • [Url]: Validates that a string is a valid URL.
  • [Range(int minimum, int maximum)]: Validates that a numeric value falls within a specified range.
  • [Compare(string otherProperty)]: Compares one property to another (e.g., for password confirmation).
  • [DataType(DataType)]: Provides semantic information about a property (e.g., DataType.Password, DataType.EmailAddress). This is often used for UI hints but can also trigger specific client-side validation.

Example Model with Data Annotations

Consider a CreateProductViewModel:


using System.ComponentModel.DataAnnotations;

public class CreateProductViewModel
{
    [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; }

    [Required]
    [Range(0.01, 1000.00, ErrorMessage = "Price must be between 0.01 and 1000.00.")]
    [DataType(DataType.Currency)]
    public decimal Price { get; set; }

    [EmailAddress(ErrorMessage = "Please enter a valid email address.")]
    public string ContactEmail { get; set; }

    [Url(ErrorMessage = "Please enter a valid website URL.")]
    public string Website { get; set; }
}
                    

Using Validation in Controllers

In your controller actions, you can check the validity of the model using the ModelState.IsValid property. This property is automatically populated based on the data annotations applied to your model and the incoming request data.

Controller action example:


using Microsoft.AspNetCore.Mvc;

public class ProductsController : Controller
{
    public IActionResult Create()
    {
        return View();
    }

    [HttpPost]
    public IActionResult Create(CreateProductViewModel model)
    {
        if (ModelState.IsValid)
        {
            // Process the valid model data (e.g., save to database)
            // ...
            return RedirectToAction("Index"); // Redirect to a success page
        }

        // If ModelState is not valid, re-render the view with validation errors
        return View(model);
    }
}
                    

Displaying Validation Messages in Views

To display validation messages to the user, you can use the <validation-summary> and <span class="field-validation-valid"> (or field-validation-error) tag helpers in your Razor views.

Razor view example (Create.cshtml):


@model CreateProductViewModel

@{
    ViewData["Title"] = "Create Product";
}

Create New Product

@section Scripts { @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} }

Note: The _ValidationScriptsPartial.cshtml typically includes the necessary JavaScript libraries (like jQuery Validate and the unobtrusive validation adapter) for client-side validation to function.

Custom Validation

For more complex validation rules that cannot be expressed with built-in attributes, you can create custom validation attributes or use the IValidatableObject interface.

Custom Validation Attribute Example:

To create a custom validation attribute, inherit from ValidationAttribute and override the IsValid method.


using System.ComponentModel.DataAnnotations;

public class NonNegativeAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        if (value is decimal decimalValue)
        {
            return decimalValue >= 0;
        }
        if (value is int intValue)
        {
            return intValue >= 0;
        }
        // Handle other numeric types as needed or return false
        return false; 
    }
}

// Usage in model:
// [NonNegative(ErrorMessage = "Value cannot be negative.")]
// public decimal Discount { get; set; }
                    

Conclusion

Effective validation is a cornerstone of building reliable web applications. By leveraging data annotations and understanding the interplay between client-side and server-side validation, you can create robust and user-friendly forms in ASP.NET Core MVC.