Я создаю приложение MVC 3, в котором используется MEF. Основная идея состоит в том, чтобы иметь механизм подключаемых модулей, в котором модели, контроллеры и представления загружаются динамически во время выполнения из контейнера mef.
Каждый плагин / модуль состоит из двух сборок:
и помещается в каталог Plugins. внутри корзины веб-приложения:
Там также является основным модулем, на который ссылаются все другие модули: ModuleCore.Data.dll и, соответственно, ModuleCore.Web.dll.
Затем в Global.asax контейнер создается следующим образом:
AggregateCatalog catalog = new AggregateCatalog();
var binCatalog = new DirectoryCatalog(HttpRuntime.BinDirectory, "Module*.dll");
var pluginsCatalot = new DirectoryCatalog(Path.Combine(HttpRuntime.BinDirectory, "Plugins"), "Module*.dll");
catalog.Catalogs.Add(binCatalog);
catalog.Catalogs.Add(pluginsCatalot);
CompositionContainer container = new CompositionContainer(catalog);
container.ComposeParts(this);
AppDomain.CurrentDomain.AppendPrivatePath(Path.Combine(HttpRuntime.BinDirectory, "Plugins"));
CustomViewEngine создается и регистрируется и используется для поиска представлений в сборке модуля:
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new CustomViewEngine());
фабрика контроллеров для загрузки контроллеров из container:
ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(_container));
, а также настраиваемый поставщик виртуального пути для получения сборок из контейнера:
HostingEnvironment.RegisterVirtualPathProvider(new ModuleVirtualPathProvider());
Итак, вся инфраструктура для обработки подключаемых моделей, контроллеров и представлений готова. Теперь все работает ... кроме одного - строго типизированных представлений .
Чтобы проиллюстрировать проблему более подробно, подготовим сцену:
Теперь мы делаем следующее:
Таким образом, похоже, что компилятор / построитель не просматривал папку bin / Plugins для Module1.Data.dll, потому что, когда я скопировал этот файл в папку bin, он был сформулирован нормально .
Вопрос / проблема: почему конструктор не заглянул в папку bin / Plugins, хотя этот каталог был добавлен методом AppDomain.CurrentDomain.AppendPrivatePath? Как однажды добавить частные пути для сборщика сборок эта папка плагинов будет принята во внимание ??
Мне удалось кое-что обойти, создав CustomRazorBuildProvider, который переопределяет стандартный:
public class CustomRazorBuildProvider : RazorBuildProvider
{
public override void GenerateCode(System.Web.Compilation.AssemblyBuilder assemblyBuilder)
{
Assembly a = Assembly.LoadFrom(Path.Combine(HttpRuntime.BinDirectory, "Plugins", "Module1.Data.dll"));
assemblyBuilder.AddAssemblyReference(a);
base.GenerateCode(assemblyBuilder);
}
}
, но недостатком этого решения является то, что каждый раз при компиляции представления ссылки на все сборки в папку Plugins необходимо добавить, что может вызвать проблемы с производительностью позже, когда будет использоваться много плагинов.
Какие-нибудь более приятные решения?