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

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

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

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

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

using System.ComponentModel.DataAnnotations;

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

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

Чтобы применить логику валидации, надо переопределить метод 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; }
}

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

@model MvcApp.Models.Person
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<form method="post">
    <div asp-validation-summary="All"></div>
        <p>
            <label asp-for="Name">Name</label><br />
            <input type="text" asp-for="Name" />
            <span asp-validation-for="Name"  />
        </p>
        <p>
            <label asp-for="Email">Email</label><br />
            <input type="text" asp-for="Email" />
            <span asp-validation-for="Email"  />
        </p>
        <p>
            <label asp-for="Password">Password</label><br />
            <input type="password" asp-for="Password" />
            <span asp-validation-for="Password"  />
        </p>
        <p>
            <label asp-for="Age">Age</label><br />
            <input asp-for="Age" />
            <span asp-validation-for="Age" />
        </p>
        <p>
            <input type="submit" value="Send"  />
        </p>
</form>

<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.5.1.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.17.0/jquery.validate.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.10/jquery.validate.unobtrusive.min.js"></script>

И после отправки имени, которое не входит в разрешенный диапазон, мы получим ошибку валидации:

Создание атрибута валидации в ASP.NET Core MVC и C#

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

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

using System.ComponentModel.DataAnnotations;

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

В данном случае параметр value уже будет представлять всю модель Person в целом. И если переданное значение действительно представляет объект Person и при этом значения его свойств Name и Password не равны, то возвращается true. А это значит, что объект 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)
    {
        var errors = new List<ValidationResult>();

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

        return errors;
    }
}

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

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