小编unt*_*dex的帖子

MEF和MVC 3 - 如何从mef容器动态加载嵌入式视图?

我正在构建一个使用MEF的MVC 3应用程序.主要思想是具有插件机制,其中模型,控制器和视图在运行时从mef容器动态加载.

每个插件/模块由两个程序集组成:

  • Module1.Data.dll(包含模型的定义)
  • Module1.Web.dll(包含控制器和视图)

并放在Web应用程序bin中的Plugins目录中:

  • 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.

然后,在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"));
Run Code Online (Sandbox Code Playgroud)

创建并注册CustomViewEngine并用于在模块程序集中查找视图:

ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new CustomViewEngine());
Run Code Online (Sandbox Code Playgroud)

控制器工厂从容器加载控制器:

ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(_container));
Run Code Online (Sandbox Code Playgroud)

以及从容器中获取程序集的自定义虚拟路径提供程序:

HostingEnvironment.RegisterVirtualPathProvider(new ModuleVirtualPathProvider());
Run Code Online (Sandbox Code Playgroud)

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

为了更详细地说明问题,让我们准备场景:

  • 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(操作方法索引在ShowUserController上执行并查看Index.cshtml被提取)
  2. 获取视图Index.cshtml后 - 编译开始(通过RazorBuildProvider)
  3. 引发异常:"无法在命名空间Module1中找到数据类型",换句话说,在动态构建视图期间无法找到UserDTO

因此,似乎编译器/构建器没有查看Module1.Data.dll的bin/Plugins文件夹,因为当我将此文件复制到bin文件夹时 - 措辞很好. …

mef dynamic-compilation strongly-typed-view razor asp.net-mvc-3

11
推荐指数
1
解决办法
1679
查看次数

具有插件和多租户支持的ASP.NET MVC应用程序与单独的AppDomain?

问题

我有一个ASP.NET MVC 3应用程序,具有插件/模块架构多租户支持.MEF用于解析依赖关系并加载可插入部分.

每个模块由控制器,视图和其他对象组成(在体育上它是一个组件).模块加载到租户.

简单配置可能如下所示:

租户1:

  • 模块A,版本1.0(ModuleA.dll)
  • 模块B,版本1.0(ModuleB.dll)

租户2:

  • 模块B,版本1.0(ModuleB.dll)

不同模块和不同版本的Dll分别存储在不同的物理位置.应用程序在一个AppDomain上运行(默认值为1).

但是,如果我们想在不同租户使用不同模块版本的情况下进行配置,我们会遇到在不同版本中加载相同程序集的问题.这意味着下面的场景不能完全正常工作,因为在从ModuleB解析类型时我们得到了组合不匹配异常(版本1.0和1.5被加载到MEF中,但是只有一个程序集已经通过程序集加载器加载到AppDomain中).

租户1:

  • 模块A,版本1.0(ModuleA.dll)
  • 模块B,版本1.0(ModuleB.dll)

租户2:

  • 模块A,版本1.5(ModuleB.dll)

解?

因此,我们提出了一个解决方案,即将不同的租户及其模块/组件加载到单独的AppDomain中.这意味着我们的示例Tenant1和Tenant2被加载到AppDomain1和AppDomain2中.在ASP.NET MVC管道中,我们连接到控制器工厂,以便选择适当的应用程序域,如下所示:

  • 请求由默认的AppDomain(Web应用程序启动的那个)处理
  • 控制器工厂
    • 从请求中获取Tenant_Id并从适当的AppDomain解析适当的控制器(我们有Tenant_Id-> Tenant-> AppDomain关系)
      • 返回ControllerProxy(它是一个实现IController的代理类,并继承MarshalByRefObject以便能够在不同的App Domians之间传递控制器)
  • 行动祈求者
    • 在控制器代理对象上调用适当的操作,现在执行在底层应用程序domian中执行
    • 在这里我们遇到了问题,因为动作调用者无法将不可序列化的RequestContext传递给另一个应用程序域(换句话说,controllerProxy.Execute(RequestContext context)抛出有关序列化的异常)

问题(S):

  • 如何以一种很好的方式在app域之间传递RequestContext(非可序列化对象)?
  • 是否可以连接到管道中的另一个步骤,以将执行重定向到基础应用程序域(在控制器工厂之前?)
  • 或者有关此问题的其他解决方案的任何想法?

asp.net-mvc serialization mef appdomain asp.net-mvc-3

5
推荐指数
1
解决办法
1830
查看次数