Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7
Встроенные атрибуты валидации охватывают большую часть возможных ситуаций, которые могут возникнуть, но все же их бывает недостаточно, особенно в каких-то специфических сценариях. Однако 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:
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 будет ошибкой только этого конкретного свойства: