Пытаясь уменьшить размер моих контроллеров MVC, я реорганизую большую часть логики в сервисы (хотя эта же проблема возникла бы, если бы она учитывалась в моделях). Я часто обнаруживаю, что я напрямую устанавливал ViewData
и/или TempData
с информацией, которую я хотел отобразить пользователю, например:
var repoUser = new UserRepository();
var foundUser = repoUser.GetUser(userId);
if (foundUser == null) {
ViewData["ErrorMessage"] = "Could not find user with ID {0}.".FormatWith(userId);
return View("UsersRegister");
}
Конечно, как только вы перейдете в сервисный класс, вы потеряете прямой доступ к ViewData
, TempData
и таким методам, как View()
или RedirectToAction()
, поэтому я пытаюсь выяснить, как с этим справиться. На ум приходят два решения:
Создайте класс, содержащий различную информацию о том, что должен делать контроллер, для передачи обратно от служб, например:
public class ResponseInfo { public string Name { get; set; } public bool DoRedirect { get; set; } public object RedirectRouteValues { get; set; } public string InfoMessage { get; set; } public string ErrorMessage { get; set; } }
Попробуйте и разрешите методам службы иметь прямой доступ к таким вещам, как
ViewData
иTempData
, например:public ActionResult ToggleUserAttended(int eventId, int userId, HttpRequestBase request, TempDataDictionary tempData, ViewDataDictionary viewData, Func<string, object, ActionResult> redirectAction) { //... var repoUser = new UserRepository(); var foundUser = repoUser.GetUser(userId); if (foundUser == null) { tempData["ErrorMessage"] = "Could not find user with ID {0}.".FormatWith(userId); return redirectAction("UsersRegister", new { id = eventId, returnUrl = request.QueryString["returnUrl"] }); } //... }
... и затем в контроллере:
return _svcEvent.ToggleUserAttended(123, 234, Request, TempData, ViewData, (name, routeVals) => RedirectToAction(name, routeVals));
Для номера 1 у контроллера будет больше логики, чтобы посмотреть на объект ResponseInfo
и определить, следует ли перенаправить, отобразить представление, вставить сообщение об ошибке или информационное сообщение в TempData
или ViewData
и т. д. Номер 2 в значительной степени позволит одно- контроллер лайнера, но вы делаете службу очень осведомленной о вещах, специфичных для контроллера. Тем не менее, служба всегда будет тесно связана с контроллером, так что это проблема? Будет ли 1 или 2 лучшей практикой или что-то еще, чего я не указал?
ActionFilter
s... Только не делайте этого, пожалуйста, не позволяйте своим службам получать доступ к интерфейсным концепциям, таким какViewData
иTempData
.. - person Simon Whitehead   schedule 19.03.2013ModelState
для отображения этих ошибок? У вас может быть карта уровня пользовательского интерфейса между списками ошибок уровня сервиса и файломModelStateDictionary
. Это отделяет вашу службу от вашего пользовательского интерфейса. Вы даже можете написать свой собственныйActionResult
, чтобы он возвращал все это красиво и значительно уменьшал размер ваших действий.. Сейчас у меня нет рядом ПК, чтобы напечатать пример. - person Simon Whitehead   schedule 19.03.2013ModelState
и его документации кажется крайне неадекватным. - person Jez   schedule 19.03.2013ModelStateDictionary
, он не будет привязан к определенному свойству объекта... но все равно будет отображаться вValidationSummary
. - person Simon Whitehead   schedule 19.03.2013ModelState
. - person Jez   schedule 19.03.2013ModelState
заключается в том, что он, по-видимому, относится к состоянию модели, используемой визуализируемым «родительским» представлением. Я использую несколько форм в одном и том же представлении и визуализирую их, используя частичные, чтобы я мог передать другую модель для этой формы. Таким образом, ошибки для этих мини-форм, по-видимому, не подходят дляModelState
для представления, содержащего партиалы. - person Jez   schedule 19.03.2013