Архитектура проекта .NET MVC / многоуровневая структура

11

При планировании архитектуры для средне-масштабного веб-приложения MVC, как вы реализуете слои, чтобы они были максимально разделены и легко тестировались? (в основном следуйте рекомендациям) Допустим, я сначала использую код для доступа к данным.

Я борюсь с тем, как определить «бизнес-логику», и как она предназначена для взаимодействия с уровнем данных. Если взять в качестве примера приложение для продажи транспортных средств, будут ли бизнес-логики классами, выполняющими такие задачи, как расчет налоговой полосы для данных транспортных средств, сравнение статистики в милю на галлон и т. Д. Что касается бизнес-объектов (например, автомобили, фургоны, мотоциклы), я бы поместил их в слой данных вместе со своим DataContextклассом.

Кроме того, что составило бы логику приложения в отличие от бизнеса - я предполагаю такие вещи, как проверка сеансов / пользовательского ввода?

Так, например, контроллер автомобиля может возвращать результат действия / просмотра, в котором перечислены десять лучших автомобилей, отфильтрованных по типу и наилучшей mpg. ICarRepositoryДопустим, у меня есть «carRepo», вставленный в мой контроллер (с использованием шаблона репозитория / DI), я отфильтрую свои автомобили по параметру метода действия, напримерvar cars = carRepo.getCarsByType("hatchback");

Итак, я сохранил знания о доступе к данным из моего контроллера с помощью репозитория, чтобы теперь не пускать бизнес-логику в контроллер с использованием модели домена - var result = new MpgCalculator (cars); - Допустим, мне нужен класс калькулятора, потому что он должен выполнять дополнительную логику для расчета максимальной эффективности использования топлива, а не просто загружать / фильтровать объекты из БД. Итак, теперь у меня есть набор данных для моего представления для рендеринга, который использовал репозиторий для извлечения из уровня доступа к данным, и специфичный для домена объект для обработки и выполнения бизнес-задач с этими данными.

Я делаю ошибки здесь? нам все еще нужно использовать шаблон репозитория или я могу просто написать код для интерфейса, чтобы отделить ORM и протестировать? По этой теме, поскольку мои конкретные dbcontext для доступа к данным находятся на уровне данных, должны ли определения интерфейсов переходить на уровень домена / бизнеса, что означает, что если технология доступа к данным когда-либо будет изменена, другие мои уровни не будут затронуты?

Из того, что я изучил до сих пор, моя структура выглядит так:

Интернет-приложение MVC -> Стандартный интернет-проект - здесь представлены модели ViewModels

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

Репозиторий абстракция нужна? -> Я слышу много споров по этому поводу, особенно при использовании ORM

Уровень данных -> классы объектов (автомобиль, фургон, мотоцикл), DbContext - уровень технологии доступа к конкретным данным

Майкл Харпер
источник

Ответы:

26

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

Презентация <---> Бизнес-логика <---> Доступ к данным

Во-первых, лучше не думать о приложении как о «приложении MVC». Это приложение, которое использует шаблон MVC в качестве компонента представления. Думая об этом таким образом, вы сможете отделить свои проблемы бизнес-логики от своих проблем презентации . Возможно, для небольших приложений вполне нормально складывать все, вплоть до доступа к базе данных, в структуру MVC, но это быстро станет непригодным для приложений среднего и крупного размера.

MVC (Презентация)

В вашем приложении компонент ASP.NET MVC должен заниматься преобразованием бизнес-данных для целей отображения (модели), отображением пользовательского интерфейса (представления) и проблемами связи, такими как маршрутизация, аутентификация, авторизация, проверка запросов, обработка ответов и лайк (контроллеры). Если у вас есть код, который делает что-то еще, он не принадлежит компоненту MVC .

Репозиторий / ORM (Доступ к данным)

Также в вашем приложении уровень доступа к данным должен касаться извлечения и хранения постоянных данных. Обычно это в форме реляционной базы данных, но существует много других способов сохранения данных. Если у вас есть код, который не читает и не хранит постоянные данные, он не относится к уровню данных . Я поделился своими мыслями о обсуждении ORM / Repository ранее в SO, но, повторюсь, я не считаю ORM тем же, что и Repository, по нескольким причинам.

Бизнес Логика

Итак, теперь у вас есть уровень представления (MVC) и уровень данных (хранилище или ORM) ... Все остальное - это уровень вашей бизнес-логики (BLL). Весь ваш код, который решает, какие данные извлекать или выполняет сложные вычисления, или принимает деловые решения, должен быть здесь. Я обычно организую свою бизнес-логику в форме «сервисов», к которым мой уровень представления может обращаться для выполнения запрошенной работы. Все мои доменные модели существуют здесь.

Ваш подход

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

Другими словами, я бы не вставлял репозиторий и MPGCalculator в контроллер, это накладывает на контроллер слишком большую ответственность (он уже обрабатывает все компоненты контроллера, о которых я упоминал выше). Вместо этого у меня будет служба в BLL, которая обрабатывает все это и передает результаты обратно контроллеру. Затем контроллер может преобразовать результаты в правильную модель и передать ее в правильное представление. Контроллер не имеет никакой бизнес-логики, и единственное, что вводится в контроллер, - это соответствующие службы BLL.

Выполнение этого означает, что ваша бизнес-логика (например, с учетом набора транспортных средств, расчета MPG и сортировки в порядке убывания ) не зависит от представления и постоянных проблем. Обычно он находится в библиотеке, которая не знает ни стратегии сохранения данных, ни стратегии представления.

Эрик Кинг
источник
Привет, Эрик, отличный ответ - что касается репозиториев, я предполагаю, что конкретные классы будут жить на уровне доступа к данным, ICarRepository и т. Д. На уровне бизнес / сервис? Тогда я мог бы внедрить сервисы в мой контроллер, которые могут содержать 1 или более репозиториев в зависимости от требований?
Майкл Харпер
@MichaelHarper Да, это звучит как очень хороший способ сделать это.
Эрик Кинг,
1
Хотя аутентификация - это проблема контроллера (разные пользовательские интерфейсы аутентифицируются по-разному), я бы сказал, что авторизация является бизнес-логикой и относится к бизнес-уровню. Ты согласен?
Том
1
@ Том Да, у тебя есть хорошая мысль. Я думал о простой авторизации, поскольку у пользователя есть доступ к этому маршруту , но может быть гораздо больше, чем это. Часть "намного больше к этому" принадлежит бизнес-уровню.
Эрик Кинг,
1
@HunterNelson Если вы отображаете в модель представления, то отображение должно происходить там, где это представление, на уровне представления. Это не имело бы смысла где-то еще.
Эрик Кинг,
0

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

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

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

wpenberthy
источник
Спасибо за ответ, Уильям. Я бы рассматривал свои бизнес-объекты / логику и доменные сущности как «модели», которые контроллер использует для обработки действий пользователя, а представления - как представления конкретных моделей, которые могут содержать группы моделей и т. Д.
Майкл Харпер,