ASP.NET MVC - Пользовательский ввод и сервис / Репозиторий - Где проводить валидацию?

Это может быть слишком самоуверенным вопросом, но вам нужна помощь!

Я пытался уточнить структуру моей программы ASP.NET MVC. Я только начал использовать его в предпросмотре 5, и это мой первый опыт разработки бизнес-приложений - так что все новое!

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

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

Вот некоторые варианты, которые я вижу:

  • Выполните проверку в Service.Method для параметров, передаваемых методу.
  • Выполните проверку в объекте представления перед вызовом Service.Method.
  • Выполните проверку в объекте представления, но заставьте Service.Method требовать ссылку на объект представления, чтобы он инициировал проверку объекта.

Я уверен, что есть еще. Мне любопытно, как другие люди обрабатывают проверку пользовательского ввода в смысле MVC. Ранее я использовал блок Enterprise Validation Block, и мне нравилось иметь возможность использовать стандартные валидаторы для всего, но я не уверен, как сделать так, чтобы он вписывался в отдельный вид объекта и уровень обслуживания. Было бы легко, если бы они (просмотр объекта / службы) были одним и тем же объектом, что, возможно, делают люди? Как я уже сказал, это все новое для меня, и я ищу лучшие практики / шаблоны.

6 ответов

Решение

Обычно я выполняю базовую проверку (обязательные поля, формат электронной почты и т. Д.) В действии контроллера при отправке формы. Затем я позволяю бизнес-уровню обрабатывать проверку, которая требует знания бизнеса. Я обычно дважды проверяю базовые вещи на бизнес-уровне, поэтому, если я раскрою эту логику через веб-сервисы или позже использую ее в другом приложении, у меня все еще будет проверка, где она наиболее важна (IMO).

На это есть несколько интересных ссылок

Лично я добавил валидацию к моим объектам сервисного уровня (первые две ссылки). Таким образом, если какой-либо метод в каком-либо контроллере решит вызвать мой метод службы... логика проверяется и помещается в одно место. СУХОЙ.

Тем не менее, у меня также есть некоторая проверка пользовательского интерфейса (3-я ссылка) .. чтобы сократить время туда и обратно.

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

  • ViewData.ModelState.AddModelError (ключ, сообщение)

НТН!

Я боялся, что не получу ответов на свой пост, рад ошибаться!

Я читал эти ссылки раньше, но, вероятно, месяц или более назад, и перечитывание их с тем, что я понимаю сейчас, было очень полезным. Мне действительно нравится сообщение Стива Сандерсона со скользящей шкалой, но хотелось бы, чтобы он показал пример проверки чего-либо в правом конце спектра.

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

public static void SavePerson(Person person)
{
    // make sure it meets some format requirement
    // in this case the object is responsible for validation and the service layer is the caller
    person.EnsureValid();

    // todo: action to verify username is unique by checking database
    // in this case the service layer is responsible for calling and implementing validation

    // todo: action to save to database
}

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

Еще одна проблема, с которой я столкнулся, - это то, что сервисный уровень начинает развиваться с логикой валидации. Может быть, разделить его на другой класс или что-то? В моем случае некоторая логика проверки может быть разделена между службами, поэтому я хотел бы подумать о СУХОМ способе реализации этого. Забавные вещи, чтобы думать о!

Ссылка Эмада Ибрагима хороша тем, что, как только я начну понимать этот процесс немного больше, я собираюсь искать способ генерировать JavaScript-проверку на стороне клиента, используя тот же набор правил без необходимости повторять код. У него уже есть это:)

Я слышал о S#arp, но не сел и не увидел, как он работает (я не уверен, что на нем много демоверсий или загрузка кода - это демо!). Я не уверен, что проверки на модели базы данных будет достаточно. Мне кажется, что в отношении базы данных было бы много действительных состояний модели, которые бизнес-логика считала бы недействительными (например, диапазоны дат / должны быть до / после / и т. Д.). Это случаи, которые поражают мой мозг:)

Кроме того, ссылка мне понравилась (гуглил ее после того, как я увидел ответ Эмада на пост Стивса с BLL и не знаю, что это значит... дух):

http://en.wikipedia.org/wiki/Business_logic_layer

Поэтому я этого не знал, но думаю, что пишу именно эту модель: объект Business Process, который обрабатывает взаимодействия с данными, и Business Entities, которые являются логическими моделями, а не моделями баз данных. Я думаю, что мне нужно начать читать некоторые более фундаментальные шаблоны и практики с этим материалом, чтобы лучше понять концепции (кажется, что многое из этого - то, что пишут люди на Java против людей.NET). Возможно, пришло время сделать шаг назад:)

Взгляните на проект S#arp Architecture. В модели выполняется проверка, чтобы гарантировать, что ни один объект не будет сохранен в базе данных в недопустимом состоянии. Это делается с помощью NHibernate.Validator и присоединением его к событиям сохранения и обновления NHibernate.

Лично для меня такой подход наиболее важен, поскольку вам не нужно дублировать логику проверки на нескольких контроллерах.

Я столкнулся с этой же проблемой в недавнем проекте. Во-первых, чтобы сформулировать проблему, я пытаюсь следовать доменно-ориентированному подходу DDD. У меня есть объекты, объединенные в агрегаты, которые могут проверять самих себя, а хранилища проверяют достоверность при сохранении. Пользовательский интерфейс также может получать информацию о достоверности из агрегата, чтобы отображать обратную связь об ошибках для клиента. Общий подход заключается в максимально возможном использовании привязки модели ASP.NET MVC и помощников по валидации / формированию пользовательского интерфейса. Это создает простой поток пользовательского интерфейса: 1) bind, 2) validate, 3) если верный, save, иначе повторно заполнить представление.

Однако не совсем очевидно, как эффективно использовать ASP.NET MVC и этот простой поток, когда задействованы службы DDD. Первоначально я разработал свои услуги как таковые:

public class SomeProcessService 
{
  public Result Execute(int anAggregateID, int anotherAggregateID, string someData) 
  {
    // validate input

    // if invalid, return failures

    // else 
    //   modify aggregates
    //   using (transaction)
    //   {
    //     save aggregates
    //     commit
    //   }

    // return success
  }
}

Проблема в том, что валидация и сохранение неразрывно связаны в методе. Чтобы использовать привязку модели MVC, нам нужно нечто, что служит моделью для привязки. Я рефакторинг на это:

public class SomeProcessService 
{
  public class Request : IValidateable
  {
    public int AggregateID {get;set;}
    public int AnotherAggregateID {get;set;}
    public string SomeData {get;set;}

    public Result Validate() 
    {
      // validation
    }
  }

  public void Execute(Request request) 
  {
    // validate input by calling request.Validate()

    // if invalid, throw new ValidationException(request)

    // else 
    //   modify aggregates
    //   using (transaction)
    //   {
    //     save aggregates
    //     commit
    //   }

    // return success
  }
}

Это позволяет повторно использовать шаблон объекта параметров для отдельной проверки правильности ввода метода. Я могу привязать к объекту SomeProcessService.Request в моем контроллере, а также получить информацию проверки там. Если все хорошо, с моего контроллера я инициирую сервисный вызов, используя объект Request в качестве параметра. Похоже, что этот подход удачно сочетает службы DDD с требованиями валидации ASP.NET MVC.

Другие вопросы по тегам