ASP.NET MVC - Пользовательский ввод и сервис / Репозиторий - Где проводить валидацию?
Это может быть слишком самоуверенным вопросом, но вам нужна помощь!
Я пытался уточнить структуру моей программы ASP.NET MVC. Я только начал использовать его в предпросмотре 5, и это мой первый опыт разработки бизнес-приложений - так что все новое!
На уровне контроллера у меня есть служебный объект, отвечающий за общение с хранилищем и заботу о всей бизнес-логике. На уровне действия у меня есть объект, который содержит все данные представления - пользовательский ввод и сгенерированный вывод - который я назову объектом просмотра (есть ли общий термин для этого?). В отличие от большинства примеров, которые я вижу, этот объект является не объектом базы данных, а объектом, специфичным для представления.
Итак, теперь я хочу добавить подтверждение пользователя. Проблема в том, что я не уверен, куда это поставить. Для меня имеет смысл сделать это на уровне сервиса. Сервисный уровень отвечает за всю бизнес-логику, а валидация - это бизнес-логика. С другой стороны, большинство платформ проверки, которые я вижу, предназначены для проверки объекта, что заставляет меня думать, что объект представления должен быть осведомлен о проверке. Наконец, есть некоторые методы проверки, которые требуют подключения к базе данных (например, проверка, имеет ли поле ввода пользователя соответствующую запись базы данных), и объект представления не имеет понятия базы данных, только служба.
Вот некоторые варианты, которые я вижу:
- Выполните проверку в Service.Method для параметров, передаваемых методу.
- Выполните проверку в объекте представления перед вызовом Service.Method.
- Выполните проверку в объекте представления, но заставьте Service.Method требовать ссылку на объект представления, чтобы он инициировал проверку объекта.
Я уверен, что есть еще. Мне любопытно, как другие люди обрабатывают проверку пользовательского ввода в смысле MVC. Ранее я использовал блок Enterprise Validation Block, и мне нравилось иметь возможность использовать стандартные валидаторы для всего, но я не уверен, как сделать так, чтобы он вписывался в отдельный вид объекта и уровень обслуживания. Было бы легко, если бы они (просмотр объекта / службы) были одним и тем же объектом, что, возможно, делают люди? Как я уже сказал, это все новое для меня, и я ищу лучшие практики / шаблоны.
6 ответов
Обычно я выполняю базовую проверку (обязательные поля, формат электронной почты и т. Д.) В действии контроллера при отправке формы. Затем я позволяю бизнес-уровню обрабатывать проверку, которая требует знания бизнеса. Я обычно дважды проверяю базовые вещи на бизнес-уровне, поэтому, если я раскрою эту логику через веб-сервисы или позже использую ее в другом приложении, у меня все еще будет проверка, где она наиболее важна (IMO).
На это есть несколько интересных ссылок
Лично я добавил валидацию к моим объектам сервисного уровня (первые две ссылки). Таким образом, если какой-либо метод в каком-либо контроллере решит вызвать мой метод службы... логика проверяется и помещается в одно место. СУХОЙ.
Тем не менее, у меня также есть некоторая проверка пользовательского интерфейса (3-я ссылка) .. чтобы сократить время туда и обратно.
Наконец, текущие библиотеки MVC имеют возможность передавать сообщения об ошибках обратно в пользовательский интерфейс... так что представление может отображать их красиво. Проверять, выписываться:-
- ViewData.ModelState.AddModelError (ключ, сообщение)
НТН!
Проверьте следующие сообщения в блоге
http://blog.codeville.net/2008/09/08/thoughts-on-validation-in-aspnet-mvc-applications/ http://www.emadibrahim.com/2008/09/08/client-server-side-validation-in-aspnet-mvc/
Я боялся, что не получу ответов на свой пост, рад ошибаться!
Я читал эти ссылки раньше, но, вероятно, месяц или более назад, и перечитывание их с тем, что я понимаю сейчас, было очень полезным. Мне действительно нравится сообщение Стива Сандерсона со скользящей шкалой, но хотелось бы, чтобы он показал пример проверки чего-либо в правом конце спектра.
В качестве примера в своем блоге он приводит: "" имена пользователей должны быть уникальными ", вероятно, будут применяться в вашей базе данных". Так что это будет что-то вроде:
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.