Вопрос

От этот вопрос, похоже , имеет смысл заставить контроллер создать Модель просмотра это более точно отражает модель, которую пытается отобразить представление, но мне любопытны некоторые соглашения (я новичок в шаблоне MVC, если это еще не было очевидно).

В принципе, у меня были следующие вопросы:

  1. Обычно мне нравится иметь один класс / файл.Имеет ли это смысл с Модель просмотра если он создается только для передачи данных с контроллера в представление?
  2. Если a Модель просмотра принадлежит своему собственному файлу, и вы используете структуру каталога / проекта, чтобы разделять вещи, где Модель просмотра файл принадлежит?В Контроллеры справочник?

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

Редактировать: Смотрю на образец Приложение для любителей закусок в CodePlex это выглядит так, как будто ViewModels являются частью Контроллеры, но мне все равно неудобно, что их нет в их собственных файлах.

Это было полезно?

Решение

Я создаю то, что я называю "ViewModel" для каждого представления.Я поместил их в папку под названием ViewModels в моем веб-проекте MVC.Я называю их в честь контроллера и действия (или представления), которые они представляют.Поэтому, если мне нужно передать данные в представление регистрации на контроллере членства, я создаю класс MembershipSignUpViewModel.cs и помещаю его в папку ViewModels.

Затем я добавляю необходимые свойства и методы для облегчения передачи данных из контроллера в представление.Я использую Automapper для перехода от моей ViewModel к модели предметной области и обратно, если это необходимо.

Это также хорошо работает для составных ViewModels, которые содержат свойства, относящиеся к типу других ViewModels.Например, если у вас есть 5 виджетов на странице индекса в контроллере членства, и вы создали ViewModel для каждого частичного просмотра - как вы передаете данные из действия индекса частичным?Вы добавляете свойство к MembershipIndexViewModel типа MyPartialViewModel и при рендеринге части вы передаете его в Model.MyPartialViewModel.

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

Я также добавлю пространство имен "MyProject.Web.ViewModels" в web.config, чтобы позволить мне ссылаться на них в любом представлении, даже не добавляя явную инструкцию import для каждого представления.Просто делает это немного чище.

Другие советы

Разделение классов по категориям (контроллеры, ViewModels, Фильтры и т.д.) - это нонсенс.

Если вы хотите написать код для домашнего раздела вашего веб-сайта (/), то создайте папку с именем Home и поместите туда HomeController, IndexViewModel, AboutViewModel и т.д.и все связанные классы, используемые Home actions.

Если у вас есть общие классы, такие как ApplicationController, вы можете поместить его в корень вашего проекта.

Зачем разделять связанные вещи (HomeController, IndexViewModel) и хранить вместе вещи, которые вообще не имеют никакого отношения (HomeController, AccountController)?


Я написал запись в блоге по поводу этой темы.

Я храню свои классы приложений во вложенной папке под названием "Core" (или отдельной библиотеке классов) и использую те же методы, что и КИГГ пример нанесения, но с некоторыми незначительными изменениями, чтобы сделать мои аппликации более СУХИМИ.

Я создаю класс BaseViewData в /Core/ViewData /, где я храню общие свойства всего сайта.

После этого я также создаю все мои классы ViewData в той же папке, которые затем являются производными от BaseViewData и имеют свойства, специфичные для просмотра.

Затем я создаю ApplicationController, от которого происходят все мои контроллеры.ApplicationController имеет общий метод GetViewData следующим образом:

protected T GetViewData<T>() where T : BaseViewData, new()
    {
        var viewData = new T
        {
           Property1 = "value1",
           Property2 = this.Method() // in the ApplicationController
        };
        return viewData;
    }

Наконец, в моем действии контроллера я делаю следующее, чтобы построить свою модель ViewData

public ActionResult Index(int? id)
    {
        var viewData = this.GetViewData<PageViewData>();
        viewData.Page = this.DataContext.getPage(id); // ApplicationController
        ViewData.Model = viewData;
        return View();
    }

Я думаю, что это работает действительно хорошо, и это сохраняет ваши представления аккуратными, а ваши контроллеры - компактными.

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

Было бы разумно иметь ваши классы ViewModel в их собственных файлах, в собственном каталоге.В моих проектах у меня есть подпапка папки Models под названием ViewModels.Вот где мои ViewModels (например ProductViewModel.cs) жить.

Здесь нет подходящего места для хранения ваших моделей.Вы можете сохранить их в отдельной сборке, если проект большой и в нем много ViewModels (объектов передачи данных).Также вы можете хранить их в отдельной папке проекта сайта.Например, в Оксит они размещены в проекте Oxite, который также содержит множество различных классов.Контроллеры в Oxite перемещены в отдельный проект, и представления тоже находятся в отдельном проекте.
В Сервер Кодек - Кэмпов ViewModels называются *Form и помещаются в проект пользовательского интерфейса в папке Models.
В MvcPress project они размещены в Data project, который также содержит весь код для работы с базой данных и немного больше (но я не рекомендовал этот подход, это только для примера)
Таким образом, вы можете видеть, что существует много точек зрения.Обычно я храню свои ViewModels (объекты DTO) в проекте сайта.Но когда у меня более 10 моделей, я предпочитаю перенести их в отдельную сборку.Обычно в этом случае я тоже переношу контроллеры на отдельную сборку.
Другой вопрос заключается в том, как легко сопоставить все данные из model с вашей ViewModel.Я предлагаю взглянуть на Автоматический преобразователь библиотека.Мне это очень нравится, оно делает всю грязную работу за меня.
И я также предлагаю посмотреть на Четкая архитектура проект.Он обеспечивает очень хорошую архитектуру для проектов и содержит множество классных фреймворков и руководств, а также отличное сообщество.

вот фрагмент кода из моих лучших практик:

    public class UserController : Controller
    {
        private readonly IUserService userService;
        private readonly IBuilder<User, UserCreateInput> createBuilder;
        private readonly IBuilder<User, UserEditInput> editBuilder;

        public UserController(IUserService userService, IBuilder<User, UserCreateInput> createBuilder, IBuilder<User, UserEditInput> editBuilder)
        {
            this.userService = userService;
            this.editBuilder = editBuilder;
            this.createBuilder = createBuilder;
        }

        public ActionResult Index(int? page)
        {
            return View(userService.GetPage(page ?? 1, 5));
        }

        public ActionResult Create()
        {
            return View(createBuilder.BuildInput(new User()));
        }

        [HttpPost]
        public ActionResult Create(UserCreateInput input)
        {
            if (input.Roles == null) ModelState.AddModelError("roles", "selectati macar un rol");

            if (!ModelState.IsValid)
                return View(createBuilder.RebuildInput(input));

            userService.Create(createBuilder.BuilEntity(input));
            return RedirectToAction("Index");
        }

        public ActionResult Edit(long id)
        {
            return View(editBuilder.BuildInput(userService.GetFull(id)));
        }

        [HttpPost]
        public ActionResult Edit(UserEditInput input)
        {           
            if (!ModelState.IsValid)
                return View(editBuilder.RebuildInput(input));

            userService.Save(editBuilder.BuilEntity(input));
            return RedirectToAction("Index");
        }
}

Мы помещаем все наши ViewModels в папку Models (вся наша бизнес-логика находится в отдельном проекте ServiceLayer).

Лично я бы посоветовал, если ViewModel не является чем-то тривиальным, то использовать отдельный класс.

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

В нашем случае у нас есть Модели вместе с Контроллерами в проекте, отдельном от представлений.

Как эмпирическое правило, мы попытались перенести и избежать большую часть содержимого ViewData["..."] в ViewModel, таким образом, мы избегаем приведений и магических строк, что хорошо.

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

Наконец, мы реализуем модель представления для каждого объекта для работы с конкретной информацией.

код в контроллере:

    [HttpGet]
        public ActionResult EntryEdit(int? entryId)
        {
            ViewData["BodyClass"] = "page-entryEdit";
            EntryEditViewModel viewMode = new EntryEditViewModel(entryId);
            return View(viewMode);
        }

    [HttpPost]
    public ActionResult EntryEdit(Entry entry)
    {
        ViewData["BodyClass"] = "page-entryEdit";            

        #region save

        if (ModelState.IsValid)
        {
            if (EntryManager.Update(entry) == 1)
            {
                return RedirectToAction("EntryEditSuccess", "Dictionary");
            }
            else
            {
                return RedirectToAction("EntryEditFailed", "Dictionary");
            }
        }
        else
        {
            EntryEditViewModel viewModel = new EntryEditViewModel(entry);
            return View(viewModel);
        }

        #endregion
    }

код в модели представления:

public class EntryEditViewModel
    {
        #region Private Variables for Properties

        private Entry _entry = new Entry();
        private StatusList _statusList = new StatusList();        

        #endregion

        #region Public Properties

        public Entry Entry
        {
            get { return _entry; }
            set { _entry = value; }
        }

        public StatusList StatusList
        {
            get { return _statusList; }
        }

        #endregion

        #region constructor(s)

        /// <summary>
        /// for Get action
        /// </summary>
        /// <param name="entryId"></param>
        public EntryEditViewModel(int? entryId)
        {
            this.Entry = EntryManager.GetDetail(entryId.Value);                 
        }

        /// <summary>
        /// for Post action
        /// </summary>
        /// <param name="entry"></param>
        public EntryEditViewModel(Entry entry)
        {
            this.Entry = entry;
        }

        #endregion       
    }

Проекты:

  • DevJet.Web ( веб-проект ASP.NET MVC )

  • DevJet.Web.App.Dictionary ( отдельный проект библиотеки классов)

    в этом проекте я создал несколько папок, таких как:DAL, BLL, BO, ВИРТУАЛЬНАЯ машина (папка для просмотра моделей)

Создайте базовый класс модели представления , который имеет обычно требуемые свойства , такие как результат операции и контекстные данные , вы также можете поместить текущие пользовательские данные и роли

class ViewModelBase 
{
  public bool HasError {get;set;} 
  public string ErrorMessage {get;set;}
  public List<string> UserRoles{get;set;}
}

В базовом классе контроллера есть метод, подобный PopulateViewModelBase(), этот метод заполнит контекстные данные и роли пользователей.hasError и ErrorMessage , установите эти свойства, если возникает исключение при извлечении данных из service / db.Привяжите эти свойства к виду, чтобы отобразить ошибку.Роли пользователей можно использовать для отображения скрытого раздела в представлении на основе ролей.

Чтобы заполнить модели представлений в разных действиях get , их можно сделать согласованными , используя базовый контроллер с абстрактным методом FillModel

class BaseController :BaseController 
{
   public PopulateViewModelBase(ViewModelBase model) 
{
   //fill up common data. 
}
abstract ViewModelBase FillModel();
}

В контроллерах

class MyController :Controller 
{

 public ActionResult Index() 
{
   return View(FillModel()); 
}

ViewModelBase FillModel() 
{ 
    ViewModelBase  model=;
    string currentAction = HttpContext.Current.Request.RequestContext.RouteData.Values["action"].ToString(); 
 try 
{ 
   switch(currentAction) 
{  
   case "Index": 
   model= GetCustomerData(); 
   break;
   // fill model logic for other actions 
}
}
catch(Exception ex) 
{
   model.HasError=true;
   model.ErrorMessage=ex.Message;
}
//fill common properties 
base.PopulateViewModelBase(model);
return model;
}
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top