Правильное использование Model vs Controller в MVC / ASP.NET MVC - PullRequest
27 голосов
/ 11 августа 2011

У меня есть класс Service с методом GetProducts (). Это инкапсулирует бизнес-логику и вызывает хранилище для получения списка продуктов.

Мое представление MVC хочет показать этот список продуктов в виде списка выбора MVC. Где правильное место для этой логики? Кажется, у меня есть 3 варианта:

  1. Модель

    Модель должна предоставлять свойство с именем ProductSelectList. Когда метод получения этого свойства вызывается представлением, Модель должна вызвать Service.GetProducts() и преобразовать результат в список SelectList перед его передачей.

    Правдоподобный аргумент: Модель должна вызывать бизнес-логику и репозиторий. Представление должно просто отображать заранее определенные данные. Контроллер не должен участвовать, за исключением передачи контекстных данных в Модель.

  2. View

    Представление должно содержать код, который напрямую вызывает Service.GetProducts() и преобразует результат во встроенный список SelectList.

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

  3. Контроллер

    Контроллер должен вызвать Service.GetProducts(), преобразовать результаты в список SelectList и передать его в модель, которая должна содержать простое свойство ProductSelectList. Представление получит доступ к этому свойству для рендеринга.

    Правдоподобный аргумент: Контроллер знает, какие параметры предоставить методу Service, поэтому он должен выполнить вызов. Модель должна быть простым заполнителем для данных, заполненных Контроллером. Задача представления - просто отобразить данные из модели.

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

Кто-нибудь хотел бы поделиться своим мнением? Это просто вопрос вкуса?

Ответы [ 9 ]

14 голосов
/ 11 августа 2011

Я лично согласен с логикой Number 3 , позволяющей контроллеру заполнять модель (или модель просмотра, как иногда дифференцируется).

  • У меня тупые взгляды и отображаются только данные.
  • У меня есть мои View View Models, которые хранят информацию, которая понадобится View, время от времени выставляя свойства «get only», которые форматируют другие свойства в более хороший формат. Если моей модели нужен доступ к моим услугам, я чувствую, что делаю что-то не так.
  • Контроллеры организуют и собирают всю информацию вместе (но не выполняют никакой реальной работы, которая остается для служб.

В вашем примере, у меня было бы действие моего контроллера, подобное:

public ActionResult Index()
{
    IndexViewModel viewModel = new IndexViewModel();
    viewModel.ProductSelectList = new SelectList(Service.GetProducts(), "Value", "Name");
    return View(viewModel);
}

и модель моего вида похожа на:

public class IndexViewModel()
{
   public SelectList ProductSelectList { get; set; }
   public int ProductID { get; set; }
}

с соответствующей частью вида, похожей на:

@Html.DropDownListFor(x => x.ProductID, Model.ProductSelectList);

Таким образом, я доволен тем, что знаю, где искать, если с чем-то есть проблема, и у всего есть свое особое место.

Однако, нет правильного пути, как всегда бывает с этими вещами. У Стивена Уолтера есть хорошая серия блогов на советы MVC . В одном из них он говорит об акценте на View Model и, хотя он не заполняет список SelectList, он все же представляет собой данные во многом аналогично его списку продуктов.

7 голосов
/ 11 августа 2011

В классической архитектуре MVC ваша модель не должна быть чем-то большим, чем контейнером для ваших данных представления, поэтому ее часто называют ViewModel .ViewModel отличается от Entity Model (s) , которыми управляет ваш сервисный уровень.

В этом случае ваш контроллер отвечает за заполнение вашей ViewModel из моделей сущностей, возвращаемых вашим сервисным уровнем..

Из-за удобства некоторые разработчики будут использовать свои объекты сервисного уровня непосредственно в своих моделях представления, но в долгосрочной перспективе, что может привести к головным болям.Одним из способов решения этой проблемы является использование инструмента, такого как AutoMapper , для автоматизации перетасовки данных в и из вашей ViewModel и моделей объектов.

Вот как может выглядеть контроллер.Обратите внимание, что такие данные, как SSN, не становятся доступными для представления, поскольку существует соответствие между вашими сущностными моделями и вашей моделью представления.

public class Customer : IEntity
{
  public string CustomerID { get; set; }
  public string SSN { get; set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }    
  public Address Address { get; set; }
}

public class CustomerEditViewModel
{
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string Address1 { get; set; }
  public string Address2 { get; set; }
  public string Country { get; set; }
  public string City { get; set; }
  public string State { get; set; }
  public string Zip { get; set; }
  public string PhoneNumber { get; set; }
}

public class CustomerController
{
  [AcceptVerbs (HttpVerbs.Get)]
  public ActionResult Edit ()
  {
    Customer customer = _customerService.GetCustomer (User.Identity.Name);

    var model = new CustomerEditViewModel ()
    {
      FirstName = customer.FirstName,
      LastName = customer.LastName,
      Address1 = customer.Address.Address1,
      Address2 = customer.Address.Address2,
      Country = customer.Address.Country,
      City = customer.Address.City,
      State = customer.Address.State,
      Zip = customer.Address.Zip,
      PhoneNumber = customer.Address.PhoneNumber,
    };

    return View (model);
  }
}
6 голосов
/ 11 августа 2011

Вы правы, что есть несколько способов справиться с этим, и это даже до рассмотрения вариантов, таких как MVP, MVVM и так далее. Поскольку вы спрашиваете об ASP.Net MVC, в частности, я буду откладывать на Microsoft:

Модель MVC содержит всю логику вашего приложения, которая не содержится в представлении или контроллере. Модель должна содержать все бизнес-логика вашего приложения, логика проверки и доступ к базе данных логика. Например, если вы используете Microsoft Entity Framework для доступ к вашей базе данных, то вы бы создали свой Entity Framework классы (ваш файл .edmx) в папке Models.

Представление должно содержать только логику, связанную с генерацией пользователя. интерфейс. Контроллер должен содержать только минимум логики требуется вернуть правильное представление или перенаправить пользователя к другому действие (управление потоком). Все остальное должно содержаться в модель.

В общем, вам следует стремиться к жирным моделям и тощим контроллерам. Ваши методы контроллера должны содержать только несколько строк кода. Если действие контроллера становится слишком толстым, тогда вы должны рассмотреть возможность перемещения логика для нового класса в папке Models.

Источник

Я бы сказал, что ваш звонок принадлежит модели.

2 голосов
/ 11 августа 2011

Следует помнить, что класс SelectList относится только к MVC. Так что, по моему мнению, это не должно быть включено ни в какую бизнес-логику, и классы моделей попадают в эту категорию. Поэтому ваш список выбора должен быть частью класса модели представления.

Вот как это работает в моих проектах:

  • Метод контроллера называется
  • Контроллер использует хранилище (другими словами, бизнес-логику) для получения данных модели
  • Контроллер преобразует данные модели при необходимости и создает объект модели представления
  • Контроллер передает модель представления в представление
  • Представление отображает данные в модели представления с ограниченной логикой для отображения или скрытия объектов и т. Д.
1 голос
/ 11 августа 2011

Я разрываюсь между вариантом 1 и вариантом 3. Я полностью исключил вариант 2, так как для меня это загрязняет представление вызовами процедур, а не просто работой уровня представления.

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

Другой вариант здесь, хотя бы, состоит в том, чтобы избежать тесной связи вида и модели, помещая Dictionary Продуктов в представление через Сервисный вызов, а затем используя представление для преобразования Dictionary в SelectList, но также дает вам возможность просто выводить информацию.

Я думаю, что это сводится к предпочтению того, где вы счастливы, имея свою логику.

1 голос
/ 11 августа 2011

Ничего из вышеперечисленного.

В моем веб-слое у меня просто есть представления HTML и JavaScript.Модель не должна попадать в поле зрения, равно как и сервисы.

У меня также есть слой инфраструктуры, который связывает сервисы и модель с представлениями.В этом слое есть ViewModels, которые представляют собой классы, которые представляют то, что будет отображаться на экране, Mappers, которые выполняют работу по получению данных из сервисов / моделей и отображают их в модель представления, и Задачи, которые выполняют такие задачи, как Сохранение,Обновление и удаление данных.

Можно поместить большую часть этой инфраструктуры в контроллеры, аналогично примеру, приведенному выше Тоддом Смитом, но я нахожу для чего-либо, кроме тривиальных представлений, контроллер наполняется кодом для загрузки данных и заполненияпосмотреть модели.Я предпочитаю отдельный класс сопоставления ответственности для каждой модели представления.Тогда мой контроллер будет выглядеть примерно так:

public class CustomerController
{
  [AcceptVerbs (HttpVerbs.Get)]
  public ActionResult Edit (int id)
  {
    return View (CustomerEditMapper.Map(id));
  }

  [AcceptVerbs (HttpVerbs.Post)]
  public ActionResult Save(CustomerEditViewModel model)
  {
    var errors = CustomerEditUpdatorCommand.Execute(model);
    ModelState.AddErrors(errors);
    return View ();
  }

}
1 голос
/ 11 августа 2011

У меня была эта проблема, когда я начал работать с MVC и нашел это решение.

Контроллер взаимодействует с сервисным уровнем.Уровень обслуживания содержит модели моего домена и выполняет всю обработку запроса от контроллеров.Сервисный уровень также возвращает ViewModels для удовлетворения запросов от контроллера.

Сервисный уровень вызывает хранилище и получает объекты, необходимые для построения ViweModels.Я часто использую Automapper для заполнения ViewModel или коллекций внутри модели представления.

Итак, мои модели представлений содержат все, что нужно View, и Контроллер не делает ничего, кроме обработки запросов и пересылки их в соответствующий обработчик службы.проблема с отображением определенных элементов, таких как списки выбора, в представлении Model.

1 голос
/ 11 августа 2011

Я собираюсь с опцией 1.

Модели - это место для вызовов бизнес-логики и т. Д.

Вид - должен отображать только то, что ViewModel уже заполнено.

Контроллер - задача Контроллера состоит в том, чтобы направлять входящий трафик (от веб-запросов) в Логику, которая отвечает за обработку запроса.Отсюда и термин « контроллер ».

Всегда есть исключения из них, но лучшее место (структурно) - это Модель.

1 голос
/ 11 августа 2011

Я бы выбрал вариант 3. В общем, я сконструирую свои приложения MVC таким образом, чтобы контроллер обращался к службе, чтобы вернуть модель (или коллекцию моделей), которые затем передаются в представление. 1001 *

Я обычно держу свои модели очень тонкими. Они представляют собой плоское представление данных с атрибутами проверки и все. Я использую сервисный (или построитель моделей) слой для построения моделей и ведения бизнес-логики на них. Некоторые люди внедряют это в модель, но я считаю, что это создает грязный проект.

Вы определенно не хотите, чтобы представление совершало какие-либо звонки вашим службам.

Обновление ...
Я предполагаю, что эта SelectList ваша модель. Если вместо этого это часть вашей модели, то вы правы, вы должны поместить ее в свою модель. Я вообще не люблю делать это вызовом метода, все же. У меня есть свойство на моей модели:

public SelectList Products { get; set; }

И пусть мой сервис или класс построителя моделей действительно заполнят его. Обычно в моих моделях нет ориентированных на данные методов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...