2013-03-19 2 views
1

При попытке уменьшить размер моих MVC-контроллеров я реорганизую много логики в сервисы (хотя эта же проблема будет применяться, если она будет учитываться в моделях). Я часто находя, что я непосредственно установка ViewData и/или TempData с информацией я хотел отображаться пользователю, например:Хорошо ли передавать TempData и/или ViewData в службы?

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(), поэтому я пытаюсь найти оптимальную практику для решения этой проблемы. Два решения приходят на ум:

  1. Создайте класс, содержащий различные части информации о том, что контроллер должен делать, чтобы быть переданы обратно от услуг, как:

    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; } 
    } 
    
  2. Try и позволяют методы обслуживания, чтобы иметь прямой доступ к вещам, как 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 быть лучшей практикой или что-то еще, что я не перечислял?

+1

БОГ НЕТ. Переместите что-то в «ActionFilter's ... Просто не делайте этого, пожалуйста, не позволяйте вашим службам обращаться к интерфейсным концепциям, таким как« ViewData »и« TempData ». –

+0

@SimonWhitehead Итак, вы в основном говорите: оставить этот материал в контроллере? Как насчет сообщений об ошибках? Более полный ответ был бы оценен. – Jez

+0

Есть ли причина, по которой вы не рассматривали использование модели ModelState для отображения этих ошибок? Вы можете иметь карту уровня пользовательского интерфейса между списками ошибок уровня сервиса и «ModelStateDictionary». Это отменит вашу службу от вашего пользовательского интерфейса. Вы даже можете написать свой собственный «ActionResult», чтобы он полностью его отобразил и значительно уменьшил ваши действия. Я сейчас не рядом с ПК, чтобы напечатать пример. –

ответ

1

Возможно, я что-то неправильно понял, но мне странно, что вы хотите предоставить информацию, касающуюся проблем с презентацией, к услугам. ИМО, это очень плохая идея, так как услуги являются бизнес-логикой и не должны зависеть от уровня представления.

Мне не нравится ни один из предложенных вами подходов, поскольку мне кажется, что они размывают линию между презентацией и услугами.

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

Обычно я создаю команду/dto на основе формы/параметров и предоставляю это для обслуживания. Тогда любой клиент службы может использовать ту же команду. Если мне нужно показать данные, я запрашиваю сервисы/репозитории для всех, что мне нужно, и сопоставляю их с формой презентации (при необходимости) и помещаю ее в ViewData/TempData/Model/Whatever.

Вот некоторые примеры (рассматривать его как псевдо-код):

[HttpPost] 
public ActionResult ChangeUserInfo(UserInfoModel model) 
{ 
    var cmd = new ChangeUserInfoCommand(CurrentUserId, model.FirstName, model.LastName); 
    try { 
     userSvc.UpdateUser(cmd); 
     return RedirectToAction(...); 
    } 
    catch(XxxxException e) { // e.g. something wrong (business logic) 
     TempData["Error"] = "an error occurred: " + e.FriendlyError(); 
     return RedirectToAction(...); // error action 
    } 
    catch(SecurityException e) { 
     throw new HttpException(404, "NotFound"); 
    } 
} 

public ActionResult ShowUsers() 
{ 
    var userInfo = svc.GetUsers().Select(u => { Id = u.id, FullName = u.First + " " + u.Last); 
    // or var userInfo = svc.GetUsers().Select(u => Mapper.To<UserDTO>(u)); 
    return View(userInfo); 

    // or without model 
    // ViewData["users"] = userInfo; 
    // return View(); 
} 

Пожалуйста, обратите внимание, что это иллюстрация - я обычно делаю это совсем по-другому, но у меня есть много других объектов инфраструктуры на месте (напримерЯ явно не обрабатываю такие исключения, мои службы иногда имеют только один метод Execute(IEnumerable<Command> cmds), у меня есть хорошая поддержка анонимных классов в качестве моделей просмотра и т. Д.)

+0

Не могли бы вы привести пример команды/dto на основе формы/параметров? – Jez

+0

Конечно, просто имейте в виду, что это иллюстрация - я обычно делаю это совсем по-другому, но у меня много другой инфраструктуры на месте. –

+0

Хм, поэтому вы полагаетесь на 100% на исключения, чтобы сообщить, что произошла ошибка в оказание услуг? Это тоже не очень хорошая практика; некоторые ошибки достаточно распространены, что они достаточно предсказуемы, чтобы не требовать исключения. – Jez

Смежные вопросы