Я на самом деле работаю над платформой расширяемости для использования поверх ASP.NET MVC. Моя структура расширяемости основана на известном контейнере Ioc: Structuremap.
Вариант использования, который я пытаюсь выполнить, прост: создайте приложение, которое должно иметь некоторые базовые функции, которые могут быть расширены для каждого клиента (= мультитенантность). Должен быть только один экземпляр размещенного приложения, но этот экземпляр можно адаптировать для каждого клиента без внесения каких-либо изменений в основной веб-сайт.
Меня вдохновила статья о многопользовательском стиле, написанная Ayende Rahien: http://ayende.com/Blog/archive/2008/08/16/Multi-Tenancy--Approaches-and-Applicability.aspx
Еще одним источником вдохновения стала книга Эрика Эванса о доменно-управляемом дизайне. Моя структура расширяемости основана на шаблоне хранилища и концепции корневых агрегатов. Чтобы иметь возможность использовать структуру, хост-приложение должно быть построено на основе репозиториев и доменных объектов. Контроллеры, репозитории или доменные объекты связываются во время выполнения с помощью ExtensionFactory.
Плагин - это просто сборка, которая содержит контроллеры, репозитории или доменные объекты, которые соответствуют определенному соглашению об именах. Соглашение об именах простое, каждый класс должен иметь префикс ID клиента, например: AdventureworksHomeController.
Чтобы расширить приложение, скопируйте сборку плагина в папку расширения приложения. Когда пользователь запрашивает страницу в корневой папке клиента, например:
http://multitenant -site.com / [CustomerID] / [контроллер] / [действие]
фреймворк проверяет, есть ли плагин для этого конкретного клиента, и создает экземпляры пользовательских классов плагинов, в противном случае он загружает значение по умолчанию один раз. Пользовательские классы могут быть Контроллеры - Хранилища или Доменные объекты. Такой подход позволяет расширить приложение на всех уровнях, от базы данных до пользовательского интерфейса, через модель домена, репозитории.
Когда вы хотите расширить некоторые существующие функции, вы создаете подключаемый модуль сборки, который содержит подклассы основного приложения. Когда вы создаете совершенно новые функции, вы добавляете новые контроллеры внутри плагина. Эти контроллеры будут загружены платформой MVC при запросе соответствующего URL. Если вы хотите расширить пользовательский интерфейс, вы можете создать новое представление внутри папки расширений и ссылаться на представление новым или подклассовым контроллером. Чтобы изменить существующее поведение, вы можете создавать новые репозитории или объекты домена или подклассы выходящих из них. Обязанность платформы - определить, какой контроллер / хранилище / объект домена должен быть загружен для конкретного клиента.
Советую взглянуть на структурную карту (http://structuremap.sourceforge.net/Default.htm) и особенно на возможности DSL реестра http://structuremap.sourceforge.net/RegistryDSL.htm.
Это код, который я использую при запуске приложения для регистрации всех подключаемых контроллеров / репозиториев или объектов домена:
protected void ScanControllersAndRepositoriesFromPath(string path)
{
this.Scan(o =>
{
o.AssembliesFromPath(path);
o.AddAllTypesOf<SaasController>().NameBy(type => type.Name.Replace("Controller", ""));
o.AddAllTypesOf<IRepository>().NameBy(type => type.Name.Replace("Repository", ""));
o.AddAllTypesOf<IDomainFactory>().NameBy(type => type.Name.Replace("DomainFactory", ""));
});
}
Я также использую ExtensionFactory, унаследованный от System.Web.MVC. DefaultControllerFactory. Эта фабрика отвечает за загрузку объектов расширения (контроллеров / реестров или объектов домена). Вы можете подключить свои собственные фабрики, зарегистрировав их при запуске в файле Global.asax:
protected void Application_Start()
{
ControllerBuilder.Current.SetControllerFactory(
new ExtensionControllerFactory()
);
}
Этот фреймворк как полнофункциональный образец сайта можно найти по адресу: http://code.google.com/p/multimvc/