@stcmd04236

Как правильно создать валидатор DataAnnotations?

Добрый день всем! Проблема такая. Создал валидатор на базе ValidationAttribute из неймспейса System.DataAnnotations для проверки полей класса. Есть класс с обязательными полями которые помечены атрибутом Requred. А также есть не отмеченные. Кастомный валидатор применяется и для обязательных и для не обязательных полей. В случае если не указаны значения для необязательных полей то после валидации выдает ошибку что и эти поля (не обязательные) тоже обязательны. По идее не обязательные поля не должные проверятся если не имеет значения.

Вот кастомный класс:

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
    sealed public class APIDataTypes : ValidationAttribute
    {
        public ApiDataType DataType { get; set; }

        public APIDataTypes( ApiDataType DataType) : base()
        {
            this.DataType = DataType;
            this.checkers = new Dictionary<ApiDataType, Func<string, bool>>()
            {
                {ApiDataType.UUID, (value) => 
                {
                    ErrorMessage = "Некорректный идентификатор.";
                    string pattern = @"^[0-9A-Fa-f]{8}\-[0-9A-Fa-f]{4}\-[0-9A-Fa-f]{4}\-[0-9A-Fa-f]{4}\-[0-9A-Fa-f]{12}$";
                    return Regex.IsMatch(value, pattern);
                }},
                {ApiDataType.Coordinate, (value)=>
                {
                    ErrorMessage = "Некорректные данные координат.";
                    string pattern = @"\d{1,3}\.\d+[;]\d{1,3}\.\d+";
                    return Regex.IsMatch(value, pattern);
                }},
                {ApiDataType.IMEI,(value) =>
                {
                    ErrorMessage = "Некорректный IMEI";
                    string pattern = @"\d{2}\-\d{6}\-\d{6}";
                    return Regex.IsMatch(value, pattern);
                }},
                {
                    ApiDataType.PhoneNumber, (value) => 
                {
                    ErrorMessage = "Некорректный номер. Номер должен состоять только из натуральных чисел. Количество символов должен быть от 12 до 15 шт.";
                    string pattern = @"\d{12,15}";
                    return Regex.IsMatch(value,pattern);
                }},
                {ApiDataType.Version, (value) =>
                {
                    ErrorMessage = "Проверьте корректность данные о версии объекта";
                    Version version = new Version();
                    return Version.TryParse(value, out version);
                }}
            };
        }

        private Dictionary<ApiDataType, Func<string, bool>> checkers;

        public override bool IsValid(object value)
        {   
            return value == null ? false : checkers[this.DataType](value.ToString());
        }
        
    }

    public enum ApiDataType
    {
        PhoneNumber,
        UUID,
        IMEI,
        Coordinate,
        Version
    }


А это класс который применен этот кастомный валидатор:

public class BeaconBindingModelUpdate
    {

        [Required]
        [APIDataTypes ( ApiDataType.UUID )]
        [Display ( Name = "Идентификатор устройства" )]
        public Guid Id { get; set; }


        [Required]
        [APIDataTypes ( ApiDataType.UUID )]
        [Display ( Name = "Идентификатор пользователья" )]
        /// <summary>
        /// Идентификатор пользователья
        /// </summary>
        public Guid UserId { get; set; }

        [Display ( Name = "Идентификатор типа устройства в системе" )]
        [APIDataTypes ( ApiDataType.UUID )]
        /// <summary>
        /// Идентификатор типа устройства в системе
        /// </summary>
        public Guid BeaconTypeId { get; set; }

        [Display ( Name = "IMEI идентификатор устройства" )]
        [APIDataTypes ( ApiDataType.IMEI )]
        /// <summary>
        /// IMEI идентификатор устройства
        /// </summary>
        public string IMEI { get; set; }

        [Display ( Name = "Версия программного обеспечения" )]
        [APIDataTypes ( ApiDataType.Version )]
        /// <summary>
        /// Версия программного обеспечения устройства
        /// </summary>
        public Version SoftwareVersion { get; set; }

        [Display ( Name = "Версия устройства" )]
        [APIDataTypes ( ApiDataType.Version )]
        /// <summary>
        /// Версия устройства
        /// </summary>
        public Version HardwareVersion { get; set; }

        [Display ( Name = "Пароль установленный на устройстве" )]
        [DataType ( DataType.Password )]
        /// <summary>
        /// Пароль установленный в устройстве
        /// </summary>
        public string DevicePassword { get; set; }

        [Display ( Name = "Номер сим карты" )]
        [APIDataTypes ( ApiDataType.PhoneNumber )]
        /// <summary>
        /// Номер сим карты который установлен в устройстве
        /// </summary>
        public string SimNumber { get; set; }

        [APIDataTypes ( ApiDataType.IMEI )]
        /// <summary>
        /// IMEI идентификатор сим карты
        /// </summary>
        public string SimIMEI { get; set; }

    }
  • Вопрос задан
  • 318 просмотров
Решения вопроса 1
1) metanit.com/sharp/mvc5
Глава 7. Метаданные и валидация модели
Аннотации данных для отображения свойств
Основы валидации
Атрибуты валидации
Валидация модели в контроллере
Отображение ошибок валидации
Создание собственной логики валидации


2) FluentValidation, модель отдельно, валидация отдельно.
https://chsakell.com/2015/08/23/building-single-pa...

public class MovieViewModel : IValidatableObject
{
    public int ID { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public string Image { get; set; }
    public string  Genre { get; set; }
    public int GenreId { get; set; }
    public string Director { get; set; }
    public string Writer { get; set; }
    public string Producer { get; set; }
    public DateTime ReleaseDate { get; set; }
    public byte Rating { get; set; }
    public string TrailerURI { get; set; }
    public bool IsAvailable { get; set; }
    public int NumberOfStocks { get; set; }
 
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        var validator = new MovieViewModelValidator();
        var result = validator.Validate(this);
        return result.Errors.Select(item => new ValidationResult(item.ErrorMessage, new[] { item.PropertyName }));
    }
}

public class MovieViewModelValidator : AbstractValidator<MovieViewModel>
    {
        public MovieViewModelValidator()
        {
            RuleFor(movie => movie.GenreId).GreaterThan(0)
                .WithMessage("Select a Genre");
 
            RuleFor(movie => movie.Director).NotEmpty().Length(1,100)
                .WithMessage("Select a Director");
 
            RuleFor(movie => movie.Writer).NotEmpty().Length(1,50)
                .WithMessage("Select a writer");
 
            RuleFor(movie => movie.Producer).NotEmpty().Length(1, 50)
                .WithMessage("Select a producer");
 
            RuleFor(movie => movie.Description).NotEmpty()
                .WithMessage("Select a description");
 
            RuleFor(movie => movie.Rating).InclusiveBetween((byte)0, (byte)5)
                .WithMessage("Rating must be less than or equal to 5");
 
            RuleFor(movie => movie.TrailerURI).NotEmpty().Must(ValidTrailerURI)
                .WithMessage("Only Youtube Trailers are supported");
        }
 
        private bool ValidTrailerURI(string trailerURI)
        {
            return (!string.IsNullOrEmpty(trailerURI) && trailerURI.ToLower().StartsWith("https://www.youtube.com/watch?"));
        }
    }
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы