Создание атрибута валидации. Самовалидация модели

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7

Последнее обновление: 08.12.2019

Встроенные атрибуты валидации охватывают большую часть возможных ситуаций, которые могут возникнуть, но все же их бывает недостаточно, особенно в каких-то специфических сценариях. Однако mvc фреймворк позволяет создавать собственные атрибуты валидации и закладывать в них свою логику.

Для этого необходимо унаследовать свой атрибут от класса ValidationAttribute и переопределить его метод IsValid().

Допустим, мы хотим, чтобы вводимое имя пользователя было ограничено некоторым диапазоном имен:

using System.ComponentModel.DataAnnotations;
using System.Linq;

public class PersonNameAttribute : ValidationAttribute
{
    //массив для хранения допустимых имен
    string[] _names;

    public PersonNameAttribute(string[] names)
    {
        _names = names;
    }
    public override bool IsValid(object value)
    {
        if (value!=null && _names.Contains(value.ToString()))
            return true;

        return false;
    }
}

Чтобы применить логику валидации, надо переопределить метод IsValid, предоставленный базовым классом. Параметр этого метода как раз и представляет то значение, которое надо валидировать.

Логика атрибута довольно проста - мы получаем массив допустимых имен. А при получении значения валидируемого свойства проверяем, имеется ли оно в этом массиве авторов, в зависимости результата возвращаем true или false.

Использование атрибута аналогично использованию других атрибутов валидации:

public class Person
{
    [PersonName(new string[] {"Tom", "Sam", "Alice" }, ErrorMessage ="Недопустимое имя")]
    public string Name { get; set; }

    public string Email { get; set; }
    public string Password { get; set; }
    public int Age { get; set; }
}

Атрибуты валидации на уровне модели

Атрибуты валидации на уровне модели применяются при проверке комбинации свойств. Например, мы не хотим, чтобы имя и пароль пользователя совпадали:

using System.ComponentModel.DataAnnotations;

public class NamePasswordEqualAttribute : ValidationAttribute
{
    public NamePasswordEqualAttribute()
    {
        ErrorMessage = "Имя и пароль не должны совпадать!";
    }
    public override bool IsValid(object value)
    {
        Person p = value as Person;
          
        if (p.Name == p.Password)
        {
            return false;
        }
        return true;
    }
}

В данном случае параметр value уже будет представлять всю модель Person в целом. И теперь мы можем применить этот атрибут ко всей модели:

[NamePasswordEqual]
public class Person
{
    public string Name { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }
    public int Age { get; set; }
}

Самовалидация и IValidatableObject

Самовалидация представляет собой процесс, при котором модель запускает механизм валидации из себя самой. И сама инкапсулирует всю логику валидации.

Для этого класс модели должен реализовать интерфейс IValidatableObject:

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

public class Person : IValidatableObject
{
    public string Name { get; set; }

    public string Email { get; set; }
    public string Password { get; set; }
    public int Age { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        List<ValidationResult> errors = new List<ValidationResult>();

        if (string.IsNullOrWhiteSpace(this.Name))
        {
            errors.Add(new ValidationResult("Введите имя!", new List<string>() { "Name" }));
        }
        if (string.IsNullOrWhiteSpace(this.Email))
        {
            errors.Add(new ValidationResult("Введите электронный адрес!"));
        }
        if (this.Age < 0 || this.Age > 120)
        {
            errors.Add(new ValidationResult("Недопустимый возраст!"));
        }

        return errors;
    }
}

В данном случае нам надо реализовать метод Validate и возвратить коллекцию объектов ValidationResult, которые и будут содержать все ошибки валидации. Если в конструктор ValidationResult передается только сообщение об ошибке, тогда данная ошибка будет относиться ко всей модели в целом. Однако с помощью второго параметра можно указать конкретный список свойств модели, к которым относится ошибка. То есть в данном случае ошибки для свойств Email и Age будут считаться ошибками для всей модели, а ошибка для Name будет ошибкой только этого конкретного свойства:

ValidationAttribute в ASP.NET Core
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850