MEF и MVC 3 - как динамически загружать встроенные представления из контейнера mef?

Я создаю приложение MVC 3, в котором используется MEF. Основная идея состоит в том, чтобы иметь механизм подключаемых модулей, в котором модели, контроллеры и представления загружаются динамически во время выполнения из контейнера mef.

Каждый плагин / модуль состоит из двух сборок:

  • Module1.Data.dll (содержит определения моделей)
  • Module1.Web.dll (содержит контроллеры и представления)

и помещается в каталог Plugins. внутри корзины веб-приложения:

  • WebApp / Bin / Plugins / Module1.Data.dll
  • WebApp / Bin / Plugins / Module1.Web.dll
  • WebApp / Bin / Plugins / Module2.Data.dll
  • WebApp / Bin / Plugins / Module2.Web.dll
  • WebApp / Bin / Plugins / ModuleCore.Data.dll
  • WebApp / Bin / Plugins / ModuleCore.Web.dll
  • и т. Д.

Там также является основным модулем, на который ссылаются все другие модули: 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());

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

Чтобы проиллюстрировать проблему более подробно, подготовим сцену:

  • Модель UserDTO находится в Module1.Data.dll
  • ShowUserController.cs находится в Module1.Web.dll / Controllers /
  • Index .cshtml находится в Module1.Web.dll / Views / ShowUser (с объявленным @model Module1.Data.UserDto)

Теперь мы делаем следующее:

  1. Запускаем приложение и переходим в HOST / ShowUser / Index (действие метод Index выполняется на ShowUserController и производится выборка представления Index.cshtml)
  2. После получения представления Index.cshtml - начинается компиляция (с помощью RazorBuildProvider)
  3. Возникают исключения: «не удается найти тип данных в пространстве имен Module1», в Другими словами, UserDTO не может быть найден во время динамического построения представления

Таким образом, похоже, что компилятор / построитель не просматривал папку 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 необходимо добавить, что может вызвать проблемы с производительностью позже, когда будет использоваться много плагинов.

Какие-нибудь более приятные решения?

11
задан untoldex 27 November 2011 в 16:53
поделиться