Проверка формы веб-приложения - дизайн для распространения ошибок домена на стороне клиента?

Проверка данных должна выполняться в следующих местах в веб-приложении:

  • Клиентская сторона: браузер. Чтобы ускорить отчет об ошибках пользователя
  • Серверная сторона: контроллер. Чтобы проверить, является ли вход пользователя синтаксически действительным (без инъекций sql, например, допустимого формата для всех переданных в полях, все обязательные поля заполняются и т.д.).
  • Серверная сторона: модель (доменный уровень). Чтобы проверить, действительно ли вход пользователя действителен (не дублирует имена пользователей, баланс аккаунта не является отрицательным и т.д.).

В настоящее время я являюсь поклонником DDD, поэтому у меня есть слои пользовательского интерфейса и домена, разделенные в моих приложениях.

Я также пытаюсь следовать правилу, эта модель домена никогда не должна содержать недопустимые данные.

Итак, как вы создаете механизм проверки в своем приложении, чтобы ошибки проверки, происходящие в домене, правильно распространялись на клиента? Например, когда модель домена вызывает исключение о дублированном имени пользователя, как правильно привязать это исключение к представленной форме?

Некоторые статьи, которые вдохновили этот вопрос, можно найти здесь: http://verraes.net/2015/02/form-command-model-validation/

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

Ответ 1

Хотя не тот же вопрос, что и этот, я думаю, что ответ тот же:

Инкапсулировать логику проверки в класс многократного использования. Эти классы обычно называются спецификациями, валидаторами или правилами и являются частью домена.

Теперь вы можете использовать эти спецификации как в модели, так и в уровне обслуживания.

Если ваш пользовательский интерфейс использует ту же технологию, что и модель, вы также можете использовать там спецификации (например, при использовании NodeJS на сервере вы можете писать спецификации в JS и использовать их в браузере, слишком).

Изменить - дополнительная информация после чата

  • Создавайте мелкозернистые спецификации, чтобы вы могли отображать соответствующие сообщения об ошибках, если сбой спецификации.
  • Не вводите бизнес-правила или спецификации в поля формы.
  • Создавайте спецификации для бизнес-правил, а не для основных задач проверки ввода (например, для проверки на нуль).

Ответ 2

Я хочу использовать подход, используемый нами в одном проекте DDD.

  • Мы создали BaseClass с полями ErrorId & ErrorMessage.
  • Каждый DomainModel получается из этого BaseClass и, следовательно, имеет два дополнительных поля ErrorId и ErrorMessage, доступные из BaseClass.

  • Всякий раз, когда возникает исключение, мы обрабатываем исключение (регистрируемся на сервере, предпринимаем соответствующие шаги для компенсации логики и извлекаем сообщение "Удобное для пользователя" из локализованного файла ресурсов локализации клиента для сообщения), а затем распространять данные как простой поток без исключения исключения или исключения.

  • На стороне клиента проверьте, не является ли ErrorMessage недействительным, затем покажите ошибку.

Это простой простой подход, который мы выполнили с момента запуска проекта.

Если это новый проект, это наименее сложный и эффективный подход, но если вы вносите изменения в большой старый проект, это может не помочь, поскольку изменения большие.

Для проверки на каждом уровне поля используйте Блок приложений проверки из Корпоративной библиотеки.

Его можно использовать как:

Украсить свойства модели домена соответствующими атрибутами:

public class AttributeCustomer 
{
    [NotNullValidator(MessageTemplate = "Customer must have valid no")]
    [StringLengthValidator(5, RangeBoundaryType.Inclusive, 
        5, RangeBoundaryType.Inclusive, 
        MessageTemplate = "Customer no must have {3} characters.")]
    [RegexValidator("[A-Z]{2}[0-9]{3}", 
    MessageTemplate = "Customer no must be 2 capital letters and 3 numbers.")]
    public string CustomerNo { get; set; }
}

Создайте экземпляр проверки, например:

Validator<AttributeCustomer> cusValidator = 
            valFactory.CreateValidator<AttributeCustomer>();

Использовать объект и выполнить проверку как:

customer.CustomerNo = "AB123";
customer.FirstName = "Brown";
customer.LastName = "Green";
customer.BirthDate = "1980-01-01";
customer.CustomerType = "VIP";

ValidationResults valResults = cusValidator.Validate(customer);

Проверьте результаты проверки как:

if (valResults.IsValid)
{
    MessageBox.Show("Customer information is valid");
}
else
{
    foreach (ValidationResult item in valResults)
    {
        // Put your validation detection logic
    }
}

Пример кода берется из Microsoft Enterprise Library 5.0 - Введение в блок проверки Эти ссылки помогут понять блок Application Validation:

http://www.codeproject.com/Articles/256355/Microsoft-Enterprise-Library-Introduction-to-V

https://msdn.microsoft.com/en-in/library/ff650131.aspx

https://msdn.microsoft.com/library/cc467894.aspx