"наследование" сайтов ASP.NET MVC из общего приложения шаблонов? (мульти аренды)

Мы создаем около 10 сайтов ASP.NET MVC, которые имеют общий набор функций (и соответствующие URL-адреса, маршруты, контроллеры, действия и представления). На всех сайтах также будет использоваться базовый набор объектов домена (например, пользователей, компаний) и базовые атрибуты для этих объектов (например, имя, адрес и т.д.).

Но каждый сайт также будет сильно настроен и расширен от базы. Например, наш сайт для крупных публичных компаний будет иметь поля "Вспомогательный" и "Фондовый символ" на объекте домена компании, а наш сайт для стартапов будет иметь атрибуты "Венчурная фирма" и "Финансирование". Внешний вид также будет значительно отличаться, хотя мы стараемся, чтобы HTML был максимально согласован (по модулю дополнительных полей формы для дополнительных атрибутов объекта домена и т.д.). Мы также будем отсеивать изображения экономно, поэтому мы можем, например, повторно использовать одну и ту же графику кнопок на сайтах.

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

Я знаком с тем, как обрабатывать многоуровневую ограниченную настройку, как вы находите в StackOverflow/SuperUser/ServerFault (или MSDN/TechNet, если на то пошло), где пользовательский интерфейс немного отличается, а модель данных - или менее идентичны. Но когда модели и пользовательский интерфейс сильно отличаются (но наследуются от общей базы), я не уверен, как действовать дальше.

Меня меньше беспокоят операционные проблемы, так как мы, вероятно, будем запускать каждый сайт в отдельном приложении и размещать их в отдельных базах данных. Я больше беспокоюсь о снижении долгосрочных расходов на обслуживание кода, повышении гибкости (например, легко добавлять новые функции в базу без разрыва производных приложений) и реализовать краткосрочную экономию средств на основе dev/test-cost, поскольку мы создаем наши 2-й, 3-й, 4-й и т.д. Сайт.

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

Я понимаю, что это очень общий вопрос, но для начинающих я ищу как руководство высокого уровня, так и конкретные советы - n-трюки для того, как применять это руководство с ASP.NET MVC, включая такие вещи, как:

  • рекомендации по разделению базы/производных в проектах Visual Studio
  • наконечники управления источником, чтобы избежать разветвления
  • подсказки схемы базы данных (FWIW, наши базы данных невелики - под 10K строк на таблицу, поэтому стоимость dev/test больше связана с проблемой, чем DB perf)
  • советы по повторному использованию контроллеров /Views/etc. соответствующие "базовым" характеристикам модели, особенно повторное использование пользовательского интерфейса для таких вещей, как формы "нового клиента", которые будут содержать базовые и производные атрибуты.

У кого-нибудь есть хороший совет для того, как создать многопользовательское приложение вроде этого?

Ответы

Ответ 1

Вот что мы делаем, и это работает очень хорошо для примерно 8 сайтов в настоящее время.

  • Определите основной проект MVC для ваших контроллеров, ViewModels, HttpApplication, маршрутов и т.д. Это скомпилируется в DLL и скомпрометирует основную часть вашего сайта.

  • Создайте базовый набор представлений по умолчанию, сценариев, изображений и т.д. для вашего сайта. Они будут использоваться как по умолчанию для ваших отдельных сайтов.

  • На клиент, создайте любые настраиваемые контроллеры, маршруты и т.д., которые вам понадобятся в проекте, который компилируется в другую dll.

  • Также для каждого клиента заново создайте все виды, сценарии, изображения, которые вы хотите использовать.

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

Второй способ получения всего рабочего - заставить ваше основное приложение загружать маршруты, контроллеры и т.д. из вашей конкретной сборки вашего клиента. Для этого я использую Managed Extensibility Framework (MEF), чтобы разоблачить один метод Register. Вызов этого метода на моем коде ассемблера клиента регистрирует маршруты и любые другие специфические для клиента потребности.

Вот общий вид структуры структуры моего сайта, при этом сначала проверяется SiteContent для просмотров:

  - AppContent
  - AppContent/Static
  - AppContent/Static/Images
  - AppContent/Static/Scripts
  - AppContent/Static/Styles
  - AppContent/Views
  - AppContent/Views/Shared

  - SiteContent
  - SiteContent/Static
  - SiteContent/Static/Images
  - SiteContent/Static/Scripts
  - SiteContent/Static/Styles
  - SiteContent/Views
  - SiteContent/Views/Shared

  - web.config
  - Global.asax

У меня есть помощники, которые я могу использовать как SiteImage и AppImage для использования в моих представлениях. Кроме того, я делаю, чтобы каждый из моих клиентских сайтов использовал определенные имена для своих основных страниц, которые я никогда не определяю в своих настройках по умолчанию для AppContent.

Я понимаю, что это общий обзор, но он работает достаточно хорошо для нас прямо сейчас.

Ответ 2

Я участвую в подобном "наборе" проектов, которые в настоящее время сосредоточены на предоставлении клиентам возможности обращаться к продуктам в Интернете, но имеют очень схожие требования к тому, какую информацию следует собирать, где единственные различия касаются отдельных частей продукта информацию или несколько иные законодательные требования.

Одна вещь, которую мы пытались сделать, - создать страницы (модели, представления и комбинации контроллеров), которые могут использоваться повторно, поэтому любое приложение может использовать страницу для захвата информации, но перенаправлять на следующую страницу, которая может быть различной в зависимости от для какого типа продукта применяется. Для этого мы используем абстрактные базовые контроллеры в виде шаблона шаблона метода, которые содержат в основном всю необходимую логику контроллера (включая методы действий с их применяемыми фильтрами действий), но затем используют абстрактные методы для выполнения конкретных действий, таких как перенаправление на следующая страница в этом процессе. Это означает, что конкретная реализация контроллера, используемого конкретными потоками страниц приложения, может содержать только один метод, который возвращает RedirectToActionResult, соответствующий следующей странице в потоке. Существует также немало других вещей, которые обрабатывают обратное движение и эти виды навигационных вещей, но с помощью фильтров действий вы можете настроить его, чтобы вам не пришлось беспокоиться об этом, как только вы его заработаете и работаете,

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

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

Это связано с тем, что мы имеем структуру проекта, состоящую из базовой dll, которая содержит абстрактные классы верхнего уровня, интерфейсы и классы полезности, а также html-помощники, фильтры действий и т.д. Затем у нас есть проекты mvc, которые содержат конкретные реализации базовых контроллеров, моделей и т.д., а также представлений и мастер-страниц.

Самое сложное - делиться мнениями, и я не думаю, что мы все еще правильно разобрались. Хотя с MVC 2.0, содержащим Areas, я думаю, что это станет проблемой, но пока у меня не было хорошей игры. (см. сообщение Скотта Гу на 2.0: http://weblogs.asp.net/scottgu/archive/2009/07/31/asp-net-mvc-v2-preview-1-released.aspx) У меня есть POCed, похоже, что она будет работать, используя базовый проект MVC, чтобы содержать общие представления, а затем расширять механизм просмотра по умолчанию для поиска этого проекта на веб-сервере при поиске вида для рендеринга (что довольно легко сделать). Области, хотя это гораздо более приятное решение.

Что касается управления версиями, мы используем svn, и я думаю, что вы разумны в отношении ветвей. Это не то, с чем нам пришлось иметь дело, но мы, вероятно, собираемся пойти с git, поскольку он, кажется, делает процесс ветвления и слияния гораздо менее болезненным.

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

Ответ 4

Один из способов сделать это - использовать ветвление в исходной системе управления.

Основная ветвь предназначена для общей функциональности. Затем у вас есть ветка для настройки и вы можете объединить изменения в настройку или вернуться к основной ветке.