Перемещение проверки модели в класс обслуживания - ASP.NET MVC
Я хочу иметь возможность выполнять проверку из моих классов обслуживания. У меня есть действие контроллера, которое выглядит примерно так:
public ActionResult Edit(Post post)
{
if(!ModelState.IsValid)
return View();
_postDataService.SavePost(post);
return View("Index");
}
Мне не нравится тот факт, что мой _postDataService.SavePost() может сохранять недопустимые данные, и я хочу переместить проверку модели в мой метод _postDataService.SavePost(). Мой вопрос: какой самый элегантный способ сделать это? И если я перенесу валидацию модели в метод Service, как я могу вернуть ошибки модели обратно в контроллер? И, наконец, куда пойдет проверка модели, например уникальность адреса электронной почты, поскольку для этого требуется доступ к некоторым данным? Из всех подобных вопросов, которые я рассмотрел, ни один из них не дает прямого способа сделать это.
Я также рассмотрел это решение, но эта статья старая, и у меня есть ощущение, что она не актуальна.
1 ответ
Я предполагаю, что вы делаете проверку, помещая атрибуты в свойства вашей модели Post / класса сущностей. Если это так, вы можете проверить на своем уровне обслуживания, выполнив это:
var results = new List<ValidationResult>();
var isValid = Validator.TryValidateObject(post,
new ValidationContext(post, null, null), results, true);
По сути, это то, что делает связыватель моделей по умолчанию, когда он проверяет и конфигурирует объект ModelState для контроллера / действия.
Прелесть этого подхода в том, что вам не нужно возвращать ошибки валидации из сервисного уровня. Вы просто будете полагаться на связыватель моделей по умолчанию для автоматического выполнения вышеуказанного кода. Если кто-то когда-нибудь попытается вызвать это действие, не проверяя ModelState.IsValid, просто попросите ваш метод сервиса вызвать исключение, чтобы напомнить ему.
Обновить после комментария
Да, мой ответ рекомендует сделать проверку дважды.
Как я к этому отношусь? Я не против Мы используем Entity Framework 4.1 с MVC и не используем объекты в MVC. Вместо этого мы используем automapper для DTO-сущностей в отдельный слой viewmodel. Наши объекты EF также снабжены атрибутами ValidationAttributes, которые EF оценивает автоматически во время любой операции DbContext.SaveChanges(). Мы применяем очень похожие атрибуты проверки к свойствам наших классов viewmodel. Это может показаться не СУХИМЫМ, и оно определенно перекрывается, но в некоторых случаях атрибуты проверки на стороне пользовательского интерфейса могут отличаться от атрибутов проверки в модели предметной области.
Мы не делаем проверку на уровне сервиса. Наш уровень обслуживания является просто координатором потока приложений и не несет ответственности за бизнес-правила. Тем не менее, проверка подлинности все еще происходит дважды в нашем приложении. Во-первых, по умолчанию связыватель модели против правил проверки модели представления. Затем, если транзакция доходит до EF, проверка выполняется в отношении сущностей. Таким образом, мы фактически проверяем 2 отдельных слоя.
Если вы думаете об этом, вы действительно решаете 2 разных вопроса. В пользовательском интерфейсе вы хотите, чтобы MVC отображал сообщения проверки для пользователей. ModelState отлично подходит для этого, так как он прекрасно подходит для проверки MVC (привязка модели / jquery / ненавязчивая / проверка клиента / и т. Д.).
И наоборот, в домене вы защищаете целостность данных и применяете бизнес-правила. Домен не заботится о отображении сообщений для пользователя. Насколько он знает, клиент может быть машиной, службой WCF или чем-то еще. Роль домена состоит в том, чтобы предотвратить возникновение транзакции, и (в нашем случае) выдает исключение, а не пытается "работать с" клиентом.