MEF和MVC 3 - 如何从MEF容器动态加载嵌入的看法? [英] MEF and MVC 3 - how to load embedded views dynamically from mef container?

查看:206
本文介绍了MEF和MVC 3 - 如何从MEF容器动态加载嵌入的看法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要建在使用MEF一个MVC 3应用程序。其主要思想是有模特的地方,控制器和视图是由MEF容器在运行时动态加载的插件机制。

I'm building an MVC 3 application where MEF is used. The main idea is to have plug-in mechanism where models, controllers and views are loaded dynamically during runtime from mef container.

每个插件/模块包括两个组件:

Each plugin/module consists of two assemblies:


  • Module1.Data.dll(包含型号定义)

  • Module1.Web.dll(包含控制器和视图)

和被放置在Plugins目录Web应用程序里面斌:

and are put in the Plugins directory inside web application bin:


  • Web应用程序/斌/插件/ 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

There is also core module that is referenced by all other modules: ModuleCore.Data.dll and respectively ModuleCore.Web.dll.

然后,在Global.asax中,容器是建立在以下方式:

Then, in Global.asax, container is build in the following way:

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());

控制器工厂从集装箱装载控制器:

controller factory for loading controllers from container:

ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(_container));

和从容器获得大会还自定义虚拟路径提供:

and also custom virtual path provider for getting assemblies from container:

HostingEnvironment.RegisterVirtualPathProvider(new ModuleVirtualPathProvider());

好了,所以处理可插拔模型,控制器和视图整个基础设施已准备就绪。现在一切正常......除了一件事 - 强类型的意见

要在更多的细节ilustrate问题,让我们prepare的情景:

To ilustrate the problem in more details, let's prepare the scene:


  • UserDTO模型位于Module1.Data.dll

  • ShowUserController.cs位于Module1.Web.dll /控制器/

  • Index.cshtml位于Module1.Web.dll /查看/ ShowUser(含宣告@model Module1.Data.UserDto)

现在我们做到以下几点:

Now we do the following:


  1. 运行应用程序并进入主机/ ShowUser /指数(action方法索引是ShowUserController执行并查看Index.cshtml被取出)

  2. 视图后Index.cshtml是牵强 - 编译开始(由RazorBuildProvider)

  3. 异常被抛出:在命名空间模块1无法找到数据类型,换句话说UserDTO找不到建设视图动态

如此看来,编译器/建设者剪掉期待通过对Module1.Data.dll斌/ Plugins文件夹,因为当我复制该文件到bin文件夹 - 这措辞的细微

So it seems that compiler/builder didnt look through bin/Plugins folder for Module1.Data.dll, because when I copied this file into bin folder - it worded fine.

问题/问题:为什么建设者没有考虑斌/ Plugins文件夹,即使被AppDomain.CurrentDomain.AppendPrivatePath方法添加该目录?
如何添加装配商曾经私有的路径,以便plugins文件夹会被考虑?

Question/problem: why builder didn't look into bin/Plugins folder even though this directory was added by AppDomain.CurrentDomain.AppendPrivatePath method? How to add private paths for assembly builder once so that plugins folder will be taken into consideration??

我设法通过创建CustomRazorBuildProvider重写标准的人做身边的一些工作:

I have managed to do some work around by creating CustomRazorBuildProvider that overrides standard one:

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文件夹中的所有程序集的引用,可时,将使用大量的插件对后来导致性能问题。

but the drawback of this solution is that everytime the view is compiled, references to all assemblies in Plugins folder need to be added, which can cause performance issues later on when lots of plugins will be used.

任何更好的解决方案?

推荐答案

下面是一个想法。

如果您按照视图模型模式则不是发送DTO的直奔视图中使用所将设在同一组件作为视图一个ViewModel的。

If you follow the View Model Pattern then instead of sending the DTO's straight to the view use a ViewModel that is would be located in the same assembly as the View.

因此​​,而不是:

UserDTO模型位于Module1.Data.dll
ShowUserController.cs位于Module1.Web.dll /控制器/
Index.cshtml位于Module1.Web.dll /查看/ ShowUser(含宣告@model Module1.Data.UserDto)

UserDTO model is located in Module1.Data.dll ShowUserController.cs is located in Module1.Web.dll/Controllers/ Index.cshtml is located in Module1.Web.dll/Views/ShowUser (with declared @model Module1.Data.UserDto)

您将有:

UserDTO模型位于Module1.Data.dll
ShowUserController.cs位于Module1.Web.dll /控制器/
UserVM位于Module1.Web.dll /的ViewModels
Index.cshtml位于Module1.Web.dll /查看/ ShowUser(含宣告@model Module1.Web.ViewModels.UserVM)

UserDTO model is located in Module1.Data.dll ShowUserController.cs is located in Module1.Web.dll/Controllers/ UserVM located in Module1.Web.dll/ViewModels Index.cshtml is located in Module1.Web.dll/Views/ShowUser (with declared @model Module1.Web.ViewModels.UserVM)

有控制器地图你DTO的到的ViewModels

Have the Controller Map your DTO's to ViewModels

请参阅 AutoMapper 以帮助映射

这篇关于MEF和MVC 3 - 如何从MEF容器动态加载嵌入的看法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆