Это вопрос, связанный с тем, как структурировать проект ASP.NET MVC для приложения среднего и большого размера.
Мне показалось, что я понял понятия MVC, но после изучения архитектуры для средних и больших приложений я запутался. (пытаясь учитывать масштабируемость, расширяемость и текущее обслуживание)
Моя путаница возникает, когда я пытаюсь подумать о том, как структурировать приложение, следуя рекомендациям "лучших практик" (из многих и многочисленных источников, включая печатные и веб-страницы).
Попытка уважать такие вещи, как
- Контроллеры должны быть очень простыми
- Принципы TDD (или, по крайней мере, подход, который облегчит тестирование в будущем)
- Разделение беспокойства
- Услуги и репозитории
- Включение зависимостей
Теперь при создании небольших (простых, простых) MVC-приложений все это в значительной степени выполняется в одном проекте (в данном случае речь идет о Visual Studio Project), а также разделение между MVC "Слои" это довольно просто папки в проекте VS (а также отдельные пространства имен).
В некоторых наших других проектах мы приняли стиль Service- > repository, поэтому этот не будет отличаться.
Мы используем Entity Framework как постоянство базы данных (первый подход DB).
Мы отделили наш доступ к БД (материал EF) в другой проект VS, поэтому у нас есть проект веб-проектов и моделей (или данных) в решении.
В веб-проекте есть контроллеры и представления, а в проекте данных есть службы, репозитории и элементы EF.
Моя путаница с моделями (или, возможно, с пониманием модели Domain Model vs View)
Если бы я попытался следовать методологии (я думаю), у меня была бы модель домена (модель, с которой связаны слои EF и репозитория), и тогда у меня будет модель представления? (модель, с которой Контроллер и представление будет иметь дело), теперь они не будут на 90% одинаковыми? Разве это не значит, что вы отделяете проблемы, просто заставляя писать код модели дважды? Как я уверен, я где-то читал, что контроллеры и представления не должны иметь модель домена?
Один из способов, к которому мы подошли, - это EF, который делает все его классы моделей частичными. Затем мы расширяем этот класс и добавляем к нему класс MetaDataType, чтобы сделать "View Model" (добавить DataAnnotations к свойствам), а затем по существу одна и та же модель передается по всем слоям, но это "лучшая" практика (там это осколок в моем сознании, что это просто не так)
например,
[MetadataType(typeof(Product_Metadata))]
public partial class Product
{
//Pretty much deliberately kept empty, just so
// the EF model class can have the attribute added
//The other side of this partial class is of course in the EF models
}
public class Product_Metadata
{
[Required]
[Display(Name = "Product name")]
public string Name { get; set; }
[Required]
[Display(Name = "Unit Cost")]
public decimal Cost { get; set; }
//etc... for the rest of the properties on the product EF model
}
Может быть, это лучший способ атаковать, но я до сих пор не встречал этот метод.
Мы создаем все службы и хранилища как интерфейсы и используем карту структуры в качестве контейнера IoC. Еще одна вещь, которую я допускаю, даже несмотря на то, что мы используем зависимость Injection, которую я все еще пытаюсь примирить с TDD, похоже, что нужно написать все дважды (целая точка DI, которую я думаю)
Я полагаю, что в конечном итоге я обращаюсь к желающим здесь, в SO, которые знают больше, чем я, о архитектуре больших приложений ASP.NET MVC для некоторой помощи и рекомендаций. Там, кажется, огромное количество информации, но все, кажется, очень концептуально. Когда я, наконец, прихожу к реализации, я теряюсь в понятиях.
ИЗМЕНИТЬ
В ответ на г-на Карла Андерсона
- Пейджинг данных в представлении - Да, полностью согласен с тем, где это место, где имеет место viewmodel и имеет смысл, но опять же является CategoryListViewModel, который имеет свойство List, является ли он списком категории viewmodel или категории модели домена
- Уязвимость при массовом присвоении - я бы подумал, что эта уязвимость будет существовать с моделью домена или моделью представления (ведь как вы настроите IsAdmin, если это действительно необходимо установить, наверняка это все равно будет на ViewModel). Я бы подумал, что это нужно будет решать на другом уровне, то есть авторизации, так что только использование роли занавеса может только установить IsAdmin
- Отображение информации о просмотре в определенном формате. Конечно, это просто связано с привязкой к модели и/или просмотром html-помощников для форматирования - то есть только с привязкой к представлению и модели. В конце концов, все модели, которые визуализируются через представление, имеют свои свойства в html и все они являются строками в этой точке, поэтому возвращаемые значения все равно должны быть проанализированы, основной принцип привязки модели, поэтому, если мне нужен пользовательский, просто напишите новое связующее устройство.
- Использование вашей модели домена больше, чем просто объекты передачи данных (DTO). На самом деле я стараюсь избегать этого как можно больше, пытаясь придерживаться того факта, что модели именно это, DTO. Но если бы этот сценарий возник, я бы, вероятно, написал метод расширения в модели домена, поскольку все методы не сериализуются в любом случае, или да, добавьте модель представления, но она, вероятно, будет содержать модель домена
- Наличие разных абстракций одной и той же информации о модели домена - согласитесь частично. У меня был бы PagedAccountListViewModel (по-прежнему будут содержать модели домена), но я бы использовал только одну модель для новой и обновленной учетной записи (я рассматриваю новую, такую же, как обновление, только что предварительно заполненную), и это будет модель домена