Я предпочитаю делать проверку входных данных в моделях представления и проверку бизнеса в моделях домена .
Другими словами, любые аннотации данных, такие какОбязательные поля, проверка длины, регулярное выражение и т. д. должны быть выполнены в моделях представления и добавлены в состояние модели при возникновении ошибки.
И, вероятно, у вас будут бизнес-правила / правила домена, основанные не только на«form», так что вы должны сделать это либо в моделях домена (выполнить проверку после их сопоставления), либо с уровнем обслуживания.
Во всех наших моделях есть метод под названием «Validate», который мы вызываем в службах перед сохранением.Они выдают пользовательские исключения, если они не проходят проверку бизнеса, которая перехватывается контроллером и также добавляется в состояние модели.
Возможно, это не всеобщая чашка чая, но она соответствует.
Пример проверки бизнеса в соответствии с запросом:
Вот пример модели домена, которая у нас есть, которая представляет собой общее «сообщение» (вопрос, фотография, видео и т. Д.):
public abstract class Post
{
// .. fields, properties, domain logic, etc
public void Validate()
{
if (!this.GeospatialIdentity.IsValidForThisTypeOfPost())
throw new DomainException(this, BusinessException.PostNotValidForThisSpatial.);
}
}
Вы видите, я проверяю бизнес-правила и выкидываю пользовательские исключения.DomainException
является нашей базой, и у нас есть много производных реализаций.У нас есть перечисление с именем BusinessException
, которое содержит значения для всех наших исключений.Мы используем методы расширения в enum для предоставления сообщения об ошибке на основе ресурсов.
Это не просто поле в модели, которую я проверяю, например, «Все сообщения должны иметь тему», потому что, хотя это является частьюдомен, это проверка входных данных в первую очередь и, таким образом, обрабатывается посредством аннотаций данных в модели представления.
Теперь контроллер:
[HttpPost]
public ActionResult Create(QuestionViewModel viewModel)
{
if (!ModelState.IsValid)
return View(viewModel);
try
{
// Map to ViewModel
var model = Mapper.Map<QuestionViewModel,Question>(viewModel);
// Save.
postService.Save(model); // generic Save method, constraint: "where TPost: Post, new()".
// Commit.
unitOfWork.Commit();
// P-R-G
return RedirectToAction("Index", new { id = model.PostId });
}
catch (Exception exc)
{
var typedExc = exc as DomainException;
if (typedExc != null)
{
// Internationalised, user-friendly domain exception, so we can show
ModelState.AddModelError("Error", typedExc.BusinessError.ToDescription());
}
else
{
// Could be anything, e.g database exception - so show generic msg.
ModelState.AddModelError("Error", "Sorry, an error occured saving the Post. Support has been notified. Please try again later.");
}
}
return View(viewModel);
}
Итак, к тому времени, когда мы получимк методу «Сохранить» в сервисе модель прошла проверку 1032 *.Затем метод Save вызывает post.Validate()
, вызывая бизнес-правила.
Если возникает исключение, контроллер перехватывает его и отображает сообщение.Если он проходит метод Save и возникает другая ошибка (90% времени, например, это Entity Framework), мы показываем общее сообщение об ошибке.
Как я уже сказал, не для всех, но это работаетхорошо для нашей команды.У нас есть четкое разделение представления и проверки домена, а также последовательный поток управления от необработанного HTTP POST к перенаправлению после успеха.
HTH