Совместное использование логики проверки домена на уровне приложений с помощью FluentValidation - PullRequest
0 голосов
/ 03 июля 2018

В нашем домене у нас есть Студент, у каждого студента есть имя, фамилия и номер студента. Бизнес-правило для номера студента состоит в том, что номер студента может быть любым числом от 1 до 99999. Поскольку эта проверка относится к слою домена, я написал для этого класс, например:

public class StudentNumber : ValueObject
    {
        public StudentNumber(int value)
        {
            if (value <= 0 || value > 99999)
            {
                throw new ArgumentOutOfRangeException(
                    nameof(value),
                    "Student number must be in range of (0,9999]");
            }

            Value = value;
        }


        public int Value { get; private set; }

        public static implicit operator StudentNumber(int value)
        {
            return new StudentNumber(value);
        }
    }

Однако лучше проверять ввод на уровне приложения. Поэтому я получил класс проверки (с помощью библиотеки FluentValidation), который можно найти ниже;

public class CreateStudentCommandValidator : AbstractValidator<CreateStudentCommand>
    {
        public CreateStudentCommandValidator()
        {
            RuleFor(m => m.StudentNumber)
                .ExclusiveBetween(0, 100000)
                .WithMessage(ErrorCodes.InvalidStudentNo);
        }
    }

В CreateStudentCommand тип данных Properntys StudentNumber является целым числом.

Этот валидатор работает, однако он нарушает правило СУХОЙ. Так как я повторяю логику валидации как на уровне домена, так и в приложении.

Вопрос есть; Какова наилучшая практика использования кода проверки домена в классе валидатора FluentValidation?

1 Ответ

0 голосов
/ 05 июля 2018

Два числа действительно в разных моделях - модель запроса и модель предметной области. Перечитывая вопрос и мой первоначальный ответ, я думаю, что вижу здесь несоответствие.

Проверка внешнего интерфейса должна быть ограничена основными типами данных. Если вы ожидаете целое число, убедитесь, что вызывающая сторона отправила целое число, даты - это даты, а строки - это строки. Это ответственность Контроллера (или любого другого, который получает запрос непосредственно от пользователя). Если пользователь отправляет недопустимое целое число, оно отклоняется на этом уровне. Здесь не выполняется проверка диапазона, мы проверяем только правильность запроса.

Затем контроллер создает команду. Роль Команды - донести желание пользователя до логики домена, которая выполняет бизнес-логику для выполнения этого желания. Мы предполагаем, что пользователь действительно хочет создать ученика с заданным номером, поэтому команда должна сообщить об этом желании в домен, то есть в команде не должно быть проверки диапазона. Проверка команд обычно выполняется только с помощью аргументов конструктора соответствующего типа.

Логика домена пытается выполнить желание пользователя и создать нового ученика с недействительным номером. Домен решает, что это недопустимое число, и выдает исключение на этом уровне, что приводит к сбою выполнения Команды. Контроллер распознает сбой выполнения команды и возвращает соответствующий сбой вызывающей стороне (или, если выполнение команды асинхронно, обрабатывает ошибку соответствующим образом).

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

...