25

最近我的重点是创建一个可以托管 3rd 方 MVC 插件的 ASP.NET MVC 应用程序。理想情况下,这些插件的开发将遵循以下规则:

  1. 插件可以在标准的 MVC 项目中开发,并且能够使用 ASP.NET MVC 框架的所有现有基础设施。
  2. 编译插件 MVC 项目并将其包含到主机 MVC 应用程序中的复杂性不应该很严重。
  3. 对 MVC 应用程序的正常开发流程的任何更改都是最低限度的

经过一些研究,我想出了以下方法来实现这一点,每种方法都有自己的优点和缺点。

方法 1 - MVC 插件程序集加载到主 MVC AppDomain

工作流程

  • 在单独的 MVC 项目中开发插件。
  • 编译程序集并通过MEF或宿主项目中的基本程序集引用(如果可能)将它和任何依赖项加载到宿主应用程序PreApplicationStartMethodAttribute中。
  • 将路由映射到插件控制器,以便将插件视为Area主机内的一个。
  • 将插件视图放入正确的区域文件夹中。需要更改布局文件,以便布局路径指向基于区域的位置,而不是应用程序的根目录(开发 MVC 项目中就是这种情况)
  • 当插件请求进入时,ASP.NET 将使用现有区域功能将请求路由到正确的控制器并在正确的位置查找视图文件。

优点

  1. 将像控制器嵌入到主机 MVC 应用程序程序集中一样无缝地工作。
  2. PreApplicationStartMethodAttribute在应用程序启动之前(项目参考)和应用程序启动之后(MEF)简单地将程序集包含到主机应用程序域中

缺点

  1. 没有沙盒 - 控制器将具有与主机相同的信任级别。

结论

这是最简单的方法,但也是最不安全的。它基本上消除了允许不受信任的开发人员创建插件的可能性,因为这些插件将具有与宿主应用程序相同的信任级别(这意味着如果宿主应用程序可以执行诸如 之类的方法System.IO.File.Delete,那么插件也可以)

方法 2 - 通过 MAF 在自己的 AppDomain 中运行的 MVC 插件程序集

这种方法旨在允许创建 MVC 插件,这些插件可以被沙箱化AppDomains并由主机通过System.Addin库使用。

结构

  1. 在主机中设置了一个路由,用于确定正在处理的 url 是否针对插件。可能有一个模式,如example.com/p/{plugin}/{controller}/{action}/{id}

  2. 具有上述模式的所有路由都映射到具有模块路由操作的主机控制器。该操作查看任何给定的路由,并根据{plugin}段确定适当的插件来处理请求。

  3. 插件视图是一个接收器/发送器对象,充当插件控制器的网关。它有一个名为AcceptRequest的方法,它接收RequestContext来自主机的 a,并返回一个ActionResult.

  4. 插件管道包含可以串行化RequestContextActionResult跨管道隔离边界传输的适配器。

执行流程

  1. 匹配插件的路由并调用插件路由控制器。

  2. 控制器将所需的插件加载到自己的插件中AppDomain并调用AcceptRequest,通过RequestContext(通过管道序列化)

  3. AcceptRequest接收上下文并根据该请求确定要执行的适当控制器(使用自定义控制器工厂)。

  4. 一旦控制器完成了请求的执行,它ActionResult会向接收者对象返回一个,然后将它ActionResult(也通过管道序列化)传递回主机AppDomain

  5. 最初调用AcceptRequest的控制器然后可以将其返回ActionResult给主机 MVC 执行管道,就好像它自己处理了请求一样。AppDomain如果愿意,可以卸载插件。

优点

插件将被沙箱AppDomain化,因此可以使用适合主机的任何权限集。

缺点

  • 必须可以序列化RequestContextActionResult.
  • 可能会破坏隔离的AppDomain.

结论

这种方法在纸上听起来不错,但我不确定序列化RequestContextandActionResult对象是否可能/可行,以及单独运行 MVC 控制器。

问题

如果代码是由受信任的开发人员创建的,则第一种方法很好。我知道我不会删除所有主机视图文件或它的 web.config 文件。但最终,如果您希望第三方开发人员为您的 MVC 应用程序创建插件,您需要能够对他们的代码进行沙箱处理。

根据我的所有研究,System.Addin当您使用基于 API 的简单类库时,该库可以轻松实现主机/插件环境。然而,当涉及到 MVC 时,似乎并不容易做到这一点。

我的一些问题是:

  1. 我在这里概述的第二种方法可行吗?
  2. 有一个更好的方法吗?
  3. 未来是否会有更简单的方法来实现 MVC 插件隔离?
4

2 回答 2

1

您最终将为每个插件创建单独的站点。这样,您可以为每个 AppPool 创建降低权限的用户,系统管理员可以将“插件”安装为在该用户下运行的网站。

任何替代方案都将展示内部平台反模式。除非您有大量时间和金钱来开发插件托管系统,否则您将陷入其中并憎恨它。我根据经验说话。

这些站点可以共享 AspnetIdentity 用户存储库,您可以将核心对象作为可以引用的 dll 提供。在 CDN 上托管您的内容(脚本文件、css、图像),以便可以引用它们。如果您想与您的子站点共享视图,请将它们编译为资源:

在 ASP.NET MVC Web 应用程序中包含预编译的视图

祝你好运!

于 2015-06-30T16:49:20.673 回答
0

恕我直言 System.AddIn 对于您尝试做的事情来说有点矫枉过正。

您熟悉System.Security.Permissions命名空间吗?如果没有,您可以查看FileIOPermission。也许您可以通过使用(为什么不,甚至扩展).NET的代码访问安全机制来沙箱化您的可扩展系统。

于 2012-05-21T15:45:51.523 回答