【发布时间】:2012-05-24 15:24:02
【问题描述】:
最近我的重点是创建一个可以托管 3rd 方 MVC 插件的 ASP.NET MVC 应用程序。理想情况下,这些插件的开发应遵循以下规则:
- 插件可以在标准 MVC 项目中开发,并且能够使用 ASP.NET MVC 框架的所有现有基础架构。
- 编译插件 MVC 项目并将其包含到主机 MVC 应用程序中的复杂性应该不高。
- 对 MVC 应用程序的正常开发流程的任何更改都是最低限度的
经过一些研究,我想出了以下方法来实现这一点,每种方法都有自己的优点和缺点。
方法 1 - MVC 插件程序集加载到主 MVC AppDomain
工作流程
- 在单独的 MVC 项目中开发插件。
- 编译程序集并通过
PreApplicationStartMethodAttribute、MEF 或宿主项目中的基本程序集引用(如果可能)将它和任何依赖项加载到宿主应用程序中。 - 映射到插件控制器的路由,以便插件在主机中被视为
Area。 - 将插件视图放入正确的区域文件夹中。需要更改布局文件,以便布局路径指向基于区域的位置,而不是应用程序的根目录(开发 MVC 项目中就是这种情况)
- 当插件请求进入时,ASP.NET 将使用现有区域功能将请求路由到正确的控制器并在正确的位置查找视图文件。
优势
- 将像控制器嵌入到主机 MVC 应用程序集中一样无缝地工作。
- 在应用程序启动之前(
PreApplicationStartMethodAttribute,项目参考)和应用程序启动之后(MEF)将程序集包含到宿主应用程序域中很简单
缺点
- 无沙盒 - 控制器将具有与主机相同的信任级别。
结论
这是最简单的方法,但也是最不安全的。它基本上消除了允许不受信任的开发人员创建插件的可能性,因为这些插件将具有与宿主应用程序相同的信任级别(这意味着如果宿主应用程序可以执行诸如 System.IO.File.Delete 之类的方法,那么插件也可以)
方法 2 - 通过 MAF 在自己的 AppDomain 中运行的 MVC 插件程序集
这种方法旨在允许创建 MVC 插件,这些插件可以被沙箱化到它们自己的 AppDomains 中,并由主机通过 System.Addin 库使用。
结构
在主机中设置了一个路由,用于确定正在处理的 url 是否针对插件。可能有
example.com/p/{plugin}/{controller}/{action}/{id}等模式
具有上述模式的所有路由都映射到具有模块路由操作的主机控制器。该操作会查看任何给定的路由,并根据
{plugin}段确定适当的插件来处理请求。插件视图是一个接收器/发送器对象,充当插件控制器的网关。它有一个名为 AcceptRequest 的方法,从主机接收
RequestContext,并返回ActionResult。插件管道包含可以序列化
RequestContext和ActionResult的适配器,以便跨管道的隔离边界进行传输。
执行流程
匹配插件的路由并调用插件路由控制器。
控制器将所需插件加载到它自己的
AppDomain并调用AcceptRequest,通过RequestContext(通过管道序列化)AcceptRequest 接收上下文并根据该请求确定要执行的适当控制器(使用自定义控制器工厂)。
一旦控制器完成了请求的执行,它会返回一个
ActionResult给接收者对象,然后接收者对象将ActionResult(也通过管道序列化)传回给主机AppDomain。最初调用 AcceptRequest 的控制器随后可以将
ActionResult返回到主机 MVC 执行管道,就好像它自己处理了请求一样。如果需要,可以卸载插件AppDomain。
优势
插件将在AppDomain 中进行沙盒处理,因此可以使用适合主机的任何权限集。
缺点
- 必须可以序列化
RequestContext和ActionResult。 - 可能会破坏隔离的
AppDomain中的其他 ASP.NET MVC 功能。
结论
这种方法在纸面上听起来不错,但我不确定序列化 RequestContext 和 ActionResult 对象是否可能/是否可行,以及单独运行 MVC 控制器。
问题
如果代码是由受信任的开发人员创建的,则第一种方法很好。我知道我不会删除所有主机视图文件或它的 web.config 文件。但最终,如果您希望第三方开发人员为您的 MVC 应用程序创建插件,您需要能够对他们的代码进行沙箱处理。
根据我的所有研究,当您使用基于 API 的简单类库时,System.Addin 库可以轻松实现主机/插件环境。然而,当涉及到 MVC 时,似乎并不容易做到这一点。
我的一些问题是:
- 我在这里概述的第二种方法可行吗?
- 有没有更好的方法来做到这一点?
- 未来是否会有更简单的方法来实现 MVC 插件隔离?
【问题讨论】:
-
MAF 是一个非常强大的工具。请注意,您首先有一些非常崇高的目标试图做到这一点。我想让你问自己,'通过让 MVC-host-site 控制插件 AppDomain 来达到什么目的'?相反,我会走使插件独立于网站的路线(使用 sep.AppPools),并促进某种带外方式让插件与主机相互通信。将所有复杂性推迟到部署时间,并使实际运行时尽可能接近标准 MVC。 (事实上,我刚刚在工作中使用过这种方法)
-
@ChrisPaynter -- 你有没有找到一个好的解决方案?我也在寻找一个,我唯一遇到的是 Umbraco 方式(中等信任时的影子复制 DLL)。
-
不,我最终放弃了它。这对我需要的东西来说太过分了。请注意,我学到了很多关于框架信任的知识,所以值得。
标签: asp.net asp.net-mvc plugins appdomain