Подтвердить что ты не робот

Как я могу реорганизовать мой код доступа к базе данных вне моего проекта MVC, но сохранить мои модели просмотра внутри?

У меня есть сайт asp.net-mvc со следующими папками:

  • Контроллеры
  • Сценарии
  • представления
  • ViewModels
  • Модели
  • DomainModel

Теперь я хочу получить доступ к большому количеству этой бизнес-логики и кода доступа к базе данных и данных в другом приложении .net(приложение для консоли Windows, а не в Интернете), поэтому я рефакторинг , чтобы удалить как можно больше материалов вне проекта MVC и в другие проекты в решении, чтобы код мог использоваться совместно с другими решениями.

У меня есть две основные проблемы:

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

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

Вот немного деталей и моего процесса:

Шаг 1 - Переместите DomainModel в другой проект - успех

Поэтому перемещение проекта DomainModel было простым (так как на нем было много необработанных объектов с какой-то бизнес-логикой),

Шаг 2 - Тонкие контроллеры - успех

Я уменьшил как можно больше моих контроллеров и переместил любую логику бизнеса или сложную логику доступа к данным в папку "Модели". Когда я попытался переместить папку моделей за пределами проекта MVC, произошло несколько вещей:

Шаг 3 - Попытка перемещения папки моделей за пределы проекта MVC - борьба

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

 public ActionResult ApplicationDetail(int id)
 {
      AppDetailViewModel applicationViewModel = Model.GenerateAppDetailViewModel(id);
      return View(applicationViewModel);
 }

Таким образом, файлы в папке Model зависят от классов ViewModel. Я хочу централизовать функцию GenerateAppDetailViewModel(), которая используется в нескольких разных контроллерах. Кроме того, в моем консольном приложении (которое отправляет сообщение по электронной почте, я часто хочу получить все данные, которые случаются на каком-то представлении, поэтому мой код "хочет" также использовать модель просмотра. Если я выведу ее из проекта MVC то я могу повторно использовать, но я думаю, что проблема с зависимостями (я не нуждаюсь в SelectListItem в моем консольном приложении, но в других случаях, когда они являются просто контейнерами для разных данных, необходимых для создания представления, которое я хочу повторно использовать)

или другая вещь, которая сломалась, была зависимость от:

System.Web.Mvc

потому что у меня много кода, который:

  • запрашивает таблицу в базе данных
  • Преобразует это в коллекцию объектов (я использую nhibernate)
  • Преобразуйте это в какой-либо объект DTO (который находится в папке ViewModels) или объект List of SelectListItem (который будет использоваться для заполнения выпадающих списков в представлении), который является частью System.web.mvc.

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

Проблема в том, что если я попытаюсь сосать мой код ViewModel в папку Model и в другой проект, то снова я застрял, потому что классы ViewModel имеют большую зависимость от

System.Web.Mvc

из-за таких вещей, как SelectListItem.

Должен ли я иметь 2 папки моделей моделей (один из проектов MVC с конкретными ссылками system.web.mvc и другой, который находится в другом проекте?). Похоже, что зависимость от SelectListItem - это то, что вызывает конфликты

В большинстве примеров, которые я видел, ViewModels имеют зависимость от System.Web.Mvc например, этот учебник

Я видел следующие вопросы:

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

4b9b3361

Ответ 1

Просмотр моделей относится к конкретному приложению. Я предполагаю, что модели просмотра будут отличаться между вашим веб-приложением и консольным приложением. Таким образом, каждое приложение определяет свои собственные модели представления и соответствующее сопоставление между моделями домена и моделями представлений. Не нужно, чтобы в ваших моделях домена были методы, которые преобразуют их для просмотра моделей, потому что таким образом вы полностью привязываете свой доменный слой к слою пользовательского интерфейса, что является наихудшей вещью. Используйте слой отображения (который будет специфичным для каждого типа приложения). AutoMapper - отличный пример уровня отображения, который вы могли бы иметь.

Не пытайтесь повторно использовать модели представления ASP.NET MVC в консольном приложении. Как вы уже выяснили, они будут содержать ссылки на System.Web.Mvc, потому что, например, dropDownList в ASP.NET MVC представлен классом IEnumerable<SelectListItem>, тогда как в консольном приложении бог знает, может быть, IEnumerable<SomeItemViewModel>.

Заключение: просмотр моделей и сопоставление между моделями домена и представления относятся к уровню пользовательского интерфейса (a.k.a ASP.NET MVC, Console, WPF,...).

Ответ 2

Я понимаю, чего вы хотите достичь, и я должен сказать вам: абсолютно нормально использовать одни и те же ViewModels для разных слоев пользовательского интерфейса. В конце концов, VM является частью шаблона MVVM, и этот шаблон касается разделения проблем. И разделение означает возможность замены слоев нижнего уровня другими реализациями. Такова цель отдельных слоев программного обеспечения (среди прочих).

  • Для начала вы должны предположить, что ваш веб-проект MVC основан на MVVM. Это мысленно поможет вам принять правильные решения. Я думаю, вы уже это сделали, поскольку используете термин ViewModel.
  • Сделать ViewModels независимым от платформы. Это возможно, и это не имеет никакого отношения к SelectListItem. В конце концов, SelectListItem просто содержит пару текста/значения параметра плюс флаг, выбранный им или нет. Вы, очевидно, можете выразить ту же информацию по-другому. После передачи этого Generic вида ViewModel в MVC вы можете преобразовать общий "SelectListItem" в MVC SelectListItem. Да, это своего рода сопоставление, и не имеет значения, происходит ли это в представлении MVC или перед передачей его в представление. Но это должно произойти на уровне пользовательского интерфейса (веб-проект MVC), так как это относится к определенному платформе.
  • Вы упомянули код доступа к данным: отдельный программный уровень, обычно абстрактно вводимый в ViewModels. Я не вижу никаких проблем с этой частью.

Следовательно, у вас будут разные уровни программного обеспечения (скорее всего, в разных библиотеках .NET): уровень доступа к данным, уровень ViewModel, веб-уровень MVC.

Существует также возможность иметь MVC ViewModels (один передан из Controller to View), определенный в проекте MVC, но они будут просто обрабатывать (возможно, принимать) общие ViewModels и выставлять вещи в условиях MVC View-specific (картирование, наследование, ваше воображение?). И это тоже нормально - в конце концов, MVC - это веб-интерфейс, и он определенно имеет специфические для платформы различия, которые необходимо обрабатывать на уровне платформы, а не раньше. MVC-специфичный ViewModel был бы хорошим местом для обработки сопоставления от общего к MVC SelectListItem.

Как только этот рефакторинг завершен, ничто не мешает вам реализовать другой уровень пользовательского интерфейса - приложение консоли, которое вы упоминаете, используя те же общие модели ViewModels, что и другой слой пользовательского интерфейса - веб-проект MVC. При использовании общих моделей ViewModels в консольном приложении, если вы сталкиваетесь с проблемами, связанными с платформой Console, вы можете придумать платформу ViewModels для платформы таким же образом, как я объяснил выше для MVC-специфичных ViewModels.

Ответ 3

Вы можете создавать viewmodels в контроллере с помощью методов расширения:

Контроллер:

 public ActionResult ApplicationDetail(int id)
 {
      var model = _serviceLayer.GetSomeModel(id); 
      var viewModel = model.CreateInstance(model);      
      return View(viewModel);
 }

Создайте этот SomeModelExtensions в проекте mvc

public class SomeModelExtensions {
      public AppDetailViewModel CreateInstance(this SomeModel model) {
           var viewModel = new AppDetailViewModel();
           // here you create viewmodel object from model with logic
           return viewModel;
      }
}

Ответ 4

В общем, я использую следующую настройку/архитектуру при размещении приложения MVC, где мне может понадобиться повторное использование моделей:

Проект MVC: все, что связано с веб-сайтом. Здесь я определяю ViewModels и сопоставляю их с моделями домена.

Модели Project: библиотека классов со всей логикой вашего домена.

Проект репозитория: это библиотека классов, которые обращаются к БД и моделям доменов.

То, как это работает, заключается в том, что проект MVC будет использовать библиотеку репозитория (надеюсь, вложенной), чтобы получить модель домена и сопоставить ее с ее собственной ViewModel.

Если вы хотите также отделить отображение, вы можете поместить слой сопоставления, как предложили другие (с использованием AutoMapper) в отдельном проекте. Слой отображения будет ссылаться на репозитории (и модели домена), в то время как приложение MVC будет ссылаться только на слой Mapping.

Проблема заключается в том, что для слоя отображения при создании ViewModels вам понадобится ссылка на System.Web.Mvc, как вы выяснили, и вы не можете избежать этого. Вот почему другие сказали, и я согласен, что у вас должен быть слой отображения для каждого проекта.

Хорошим способом обойти это является наличие дополнительного общего слоя сопоставления с классами отображения, определенными для общих случаев (например, электронной почты). Затем в определенных дочерних классах вы можете определить отображение для определенных случаев (например, в зависимости от System.Web.Mvc).

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

    MVC App                      Console App
       |                            |
       |                            |
   MVC Specific Mapper         Console Specific Mapper
                 \               /  
                  \             /
                   \           /   
                   GenericMapper <- EmailMapper and EmailViewModel can be implemented here
                     |       |      
                     |       |
                Repository   |
                     |       |
                     |       |
                    DomainModels  

Вышеизложенное не является свободным от борьбы и, вероятно, усилие расщепления разбиения не стоит свечи, если есть только один или два обычных случая. Таким образом, из Generic Mapper вы свободны от библиотеки System.Web.Mvc, хотя выше вы можете забыть о коде доступа к БД (в некотором смысле, Mapper будет выступать в качестве репозитория для приложения).

Ответ 5

Я предполагаю, что веб-сайт MVC будет использовать те же данные, что и консольное приложение + дополнительные поля, правильно?

Итак, как насчет наследования вашей ViewModel от Model? Таким образом, вы сможете повторно использовать модель и получить необходимые поля в ViewModel по мере необходимости.

public class AppDetailModel
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }


    public class AppDetailViewModel : AppDetailModel
    {
        public string ViewProperty { get; set; }
    }