Как я могу рефакторинг мой код доступа к базе данных за пределами моего проекта MVC, но сохранить свои ViewModel внутри?
у меня есть asp.веб-сайт net-mvc со следующими папками:
- контроллеры
- Скрипты
- вид
- ViewModels
- модели
- файле domainmodel
теперь я хочу получить доступ к этой бизнес-логике и коду доступа к базе данных и данным в другом приложении .net (консольное приложение для windows, а не в интернете), поэтому я рефакторинг удалить как можно больше вещей за пределами MVC проект и в другие проекты в решении, чтобы код можно было совместно использовать с другими решениями.
у меня 2 основных вопроса;
моя главная проблема заключается в том, что я изо всех сил пытаюсь найти место для размещения кода, который генерирует ViewModel, потому что много этого кода я хотел бы повторно использовать в своем консольном приложении, поскольку консольное приложение отправляет электронную почту, которая требует тех же данных, что и в представлении.
еще одна главная проблема заключается в том, что я я изо всех сил пытаюсь увидеть, как я могу переместить код доступа к базе данных из проекта MVC, все еще имея ViewModels внутри, когда многие из моих функций, которые создают мои viewmodels, начинаются с кучей кода доступа к базе данных.
вот немного деталей и мой процесс до сих пор:
Шаг 1-переместить DomainModel в другой проект-Успех
поэтому перемещение проекта DomainModel было простым (так как это было много необработанных объектов с некоторыми бизнес-логика сверху - ничего веб об этом).
Шаг 2-тонкие контроллеры - успех
я уменьшил как можно больше своих контроллеров и переместил любую бизнес-логику или сложную логику доступа к данным в папку Models. Когда я попытался переместить папку models за пределы проекта MVC, несколько вещей сломались:
Шаг 3-попытка переместить папку модели за пределы проекта MVC-борьба
в истончении контроллеров у меня есть количество различных действий контроллера, которые идут в класс модели и возвращают мою ViewModel, которую я передаю обратно в представление. Что-то вроде этого (в моем классе контроллера):
public ActionResult ApplicationDetail(int id)
{
AppDetailViewModel applicationViewModel = Model.GenerateAppDetailViewModel(id);
return View(applicationViewModel);
}
таким образом, файлы в моей папке модели зависят от классов ViewModel. Я хочу централизовать функцию GenerateAppDetailViewModel (), поскольку она используется в нескольких разных контроллерах. Кроме того, в моем консольном приложении (которое отправляет электронную почту, я часто хочу получить все данные, которые находятся на некотором представлении, поэтому мой код "хочет" также использовать viewmodel .. если я перемещу его из проекта MVC, то я могу повторно использовать, но я думаю, что проблема зависимости (очевидно, мне не нужен SelectListItem в моем консольном приложении, но в других случаях, когда они являются просто объектами контейнера разных данных, необходимых для создания представления, которое я хочу повторно использовать)
и еще одна вещь, которая сломалась была зависимость:
System.Web.Mvc
потому что у меня есть много кода:
- запрашивает таблицу в a база данных
- преобразует это в коллекцию объектов (я использую nhibernate)
- преобразуйте это в какой-либо объект DTO (который находится в папке ViewModels) или список объектов SelectListItem (которые будут использоваться для заполнения раскрывающихся списков в представлении), который является частью системы.сеть.в MVC.
Я хотел найти предложения о лучшем способе вырваться из этой зависимости, чтобы я мог переместить как можно больше кода из проекта MVC для повторного использования.
проблема в том, что если я попытаюсь засосать свой код ViewModel в папку модели и в другой проект, я снова застряну, потому что классы ViewModel имеют большую зависимость от
5 ответов
модели просмотра специфичны для конкретного приложения. Я предполагаю, что модели представления будут отличаться между вашим веб-приложением и консольным приложением. Поэтому каждое приложение определяет свои собственные модели представления и соответствующее сопоставление между моделями домена и моделями представления. У ваших моделей домена нет методов, которые преобразуют их в модели просмотра, потому что таким образом вы полностью привязываете свой слой домена к слою пользовательского интерфейса, что является худшим, что может произойти. Использовать слой отображения (который будет специфичен для каждого типа приложения). AutoMapper
является отличным примером слоя отображения, который вы могли бы иметь.
даже не пытайтесь повторно использовать ASP.NET модели представления MVC в консольном приложении. Как вы уже выяснили, они будут содержать ссылки на System.Сеть.Mvc, потому что, например, dropDownList в ASP.NET MVC представлен с IEnumerable<SelectListItem>
класс тогда как в консольном приложении, бог знает, может быть IEnumerable<SomeItemViewModel>
.
вывод: Просмотр моделей и сопоставление между моделями домена и представления принадлежат к уровню пользовательского интерфейса (a.к. а ASP.NET MVC, консоль, WPF, ...).
Я понимаю, чего вы хотите добиться, и должен вам сказать: это абсолютно normal для повторного использования одних и тех же ViewModels для разных слоев пользовательского интерфейса. В конце концов, VM является частью шаблона MVVM, и этот шаблон-все о отделения проблемы. И, разделение означает возможность замены слоев нижнего уровня другими реализациями. Это is назначение отдельных программных слоев (среди прочего).
- для начала, вы необходимо предположить, что ваш веб-проект MVC основан на MVVM. Это поможет Вам принимать правильные решения. Я думаю, вы уже сделали это, так как вы используете
ViewModel
термин. - сделайте ViewModels независимой от платформы. Возможно, и это не имеет ничего общего с
SelectListItem
. В конце концов, SelectListItem просто содержит пару текст/значение параметра, а также флаг, выбран он или нет. Очевидно, что вы можете выразить ту же информацию по-другому. После прохождения этого родового вида ViewModel в MVC, вы можете преобразовать общий "SelectListItem" в MVCSelectListItem
. Да, это своего рода сопоставление, и не имеет значения, происходит ли оно в представлении MVC или перед передачей его в представление. Но это должно произойти на уровне пользовательского интерфейса (веб-проект MVC), так как это проблема отображения платформы. - вы упомянули код доступа к данным: это отдельный программный слой, обычно абстрактно вводимый в ViewModels. Я не предвижу никаких проблем с этим часть.
следовательно, у вас будут разные программные слои (скорее всего, в разных библиотеках .NET): слой доступа к данным, слой ViewModel, веб-слой MVC.
существует возможность иметь MVC ViewModels также (один передается от контроллера к виду), определенные в проекте MVC, но они будут просто обрабатывать (возможно, принимая) общие ViewModels и подвергая вещи в MVC View-конкретных терминах (отображение, наследование, ваше воображение?). И это тоже нормально - в конце концов, MVC-это веб-интерфейс, и у него определенно есть отличия от платформы, которые должны обрабатываться на уровне платформы, а не раньше. MVC specific ViewModel будет хорошим местом для обработки сопоставления от generic до MVC SelectListItem
.
как только этот рефакторинг будет выполнен, ничто не помешает вам реализовать другое приложение UI layer - Console, которое вы упоминаете, используя то же самое generic ViewModels как другой уровень пользовательского интерфейса - Веб-проект MVC. При использовании универсальных ViewModels в консольном приложении, если вы сталкиваетесь с проблемами, специфичными для консольной платформы, вы можете придумать специфические для платформы ViewModels таким же образом, как я объяснил выше для специфичных для MVC ViewModels.
вы можете создавать 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;
}
}
В общем, я использую следующую настройку / архитектуру при размещении приложения MVC, где мне может потребоваться повторно использовать модели:
проект MVC: все, что связано с интернетом. Я определяю ViewModels здесь и сопоставляю их с моделями домена.
Models Project: библиотека классов со всей логикой домена.
проект репозитория: это библиотека классов, которая обращается к БД и моделям доменов.
способ его работы заключается в том, что проект MVC будет использовать (надеюсь, введена) библиотека репозитория, чтобы получить модель домена и сопоставить ее с собственной ViewModel.
Если вы также хотите отделить отображение, вы можете поместить слой отображения, как предлагали другие (используя AutoMapper в конечном итоге), в отдельный проект. Слой сопоставления будет ссылаться на репозитории (и модели доменов), в то время как приложение MVC будет ссылаться только на слой сопоставления.
проблема в том, что слой отображения при создании ViewModels будет нуждаться в ссылка на систему.Сеть.Mvc, как вы узнали, и вы не можете избежать этого. Вот почему другие сказали, и я согласен, что у вас должен быть слой отображения для каждого проекта.
хороший способ обойти это-иметь дополнительный общий слой отображения с классами отображения, определенными для общих случаев (например, электронная почта). Затем в определенных дочерних классах вы можете определить отображение для определенных случаев (например, в зависимости от системы.Сеть.В MVC).
Так конец стека будет что-то вроде следующего, зависимости идут вниз. Конечно все должно быть в интерфейсе.
MVC App Console App
| |
| |
MVC Specific Mapper Console Specific Mapper
\ /
\ /
\ /
GenericMapper <- EmailMapper and EmailViewModel can be implemented here
| |
| |
Repository |
| |
| |
DomainModels
вышеизложенное не является свободной борьбой, и, вероятно, усилие разделения отображения на части не стоит свеч, если есть только один или два общих случая. Таким образом, от общего картографа вниз вы свободны от системы.Сеть.Библиотека Mvc, в то время как выше вы можете забыть о Коде доступа к БД (в некотором смысле картограф будет выступать в качестве репозитория для приложения).
Я предполагаю, что MVC web будет использовать те же данные, что и консольное приложение + дополнительные поля, верно?
Итак, как насчет наследования вашей ViewModel от модели? Таким образом, Вы сможете повторно использовать модель и получать пользовательские поля в ViewModel по мере необходимости.
public class AppDetailModel
{
public int ID { get; set; }
public string Name { get; set; }
}
public class AppDetailViewModel : AppDetailModel
{
public string ViewProperty { get; set; }
}