我正在構建一個使用MEF的MVC 3應用程序。主要思想是在mef容器的運行期間有模型,控制器和視圖動態加載的插件機制。MEF和MVC 3 - 如何從mef容器動態加載嵌入視圖?
每個插件/模塊包括兩個組件:
- Module1.Data.dll(包含的模型定義)
- Module1.Web.dll(包含控制器和視圖)
並放在Web應用程序bin內的Plugins目錄中:
- WebApp/Bin/Plugins/Module1.Data.dll
- Web應用程序/濱/插件/ Module1.Web.dll
- Web應用程序/濱/插件/ Module2.Data.dll
- Web應用程序/濱/插件/ Module2.Web.dll
- Web應用程序/濱/插件/ModuleCore.Data.dll
- Web應用程序/斌/插件/ 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());
控制器從容器加載控制器的工廠:
ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(_container));
,也從容器獲取組件自定義虛擬路徑提供:
HostingEnvironment.RegisterVirtualPathProvider(new ModuleVirtualPathProvider());
好了,所以處理可插拔模型,控制器和視圖的整個基礎設施已經準備就緒。現在一切正常...除了一件事 - 強烈鍵入意見。
要ilustrate的問題更多的細節,讓我們準備的一幕:
- UserDTO模型位於Module1.Data.dll
- ShowUserController.cs位於Module1.Web.dll /控制器/
- Index.cshtml位於Module1.Web.dll/Views/ShowUser(聲明爲@model Module1.Data。UserDto)
現在我們做到以下幾點:
- 運行應用程序並進入主機/ ShowUser /指數(action方法指數上ShowUserController執行並查看Index.cshtml被取出)
- 在獲取視圖Index.cshtml之後 - 編譯開始(由RazorBuildProvider提供)
- 引發異常:「在命名空間Module1中找不到數據類型」,換句話說在動態構建視圖期間無法找到UserDTO
因此,似乎編譯器/生成器沒有通過Module1.Data.dll的bin/Plugins文件夾查看,因爲當我將此文件複製到bin文件夾中時 - 它措辭良好。
問題:爲什麼builder沒有查看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文件夾中的所有程序集的引用需要被添加,這會在將來會使用大量插件時導致性能問題。
任何更好的解決方案?
你有沒有得到這個解決?我現在正試圖解決與我的MVC應用程序相同的問題。你有沒有任何資源正在運行,我可能會看看? – Coppermill
是的,我通過CustomRazorBuildProvider解決了上述問題。 Hovewer從那時起,我們的應用程序越來越多地使用MVVM方法,在這種方法中使用較少的剃刀視圖,並且構建更純淨的html/javascript視圖。 – untoldex