【问题标题】:A plugin framework with ASP.NET MVC3 and embedded Razor views具有 ASP.NET MVC3 和嵌入式 Razor 视图的插件框架
【发布时间】:2011-06-24 09:23:03
【问题描述】:

我正在使用 Razor 视图为 ASP.NET MVC3 设计插件框架,但在让嵌入式视图正常工作时遇到问题。

插件框架旨在具有以下功能:

  • 每个插件都有自己的模型、控制器和视图。视图是嵌入式资源,控制器派生自 PluginController 类
  • 插件具有对定义 PluginController 基类的共享类库的依赖项引用
  • 托管插件的“shell”Web 应用程序在设计时不得包含对任何插件的引用,因为它在设计时不知道它有哪些插件。
  • 插件 dll 被放置在 shell 应用程序的文件夹中,该文件夹不是 /bin 文件夹
  • shell 负责:
    1. 发现插件(使用反射)
    2. 注册所有控制器(为此我使用 Spring.Net)
    3. 为控制器创建路由
    4. 通过自定义 VirtualPathProvider 提供 razor 文件 (cshtml)

现在一切正常,除非嵌入式视图引用了插件 dll 中的类型。然后我得到了臭名昭著的错误(名字被忽略了):

The type or namespace name '[Plugins]' does not exist in the namespace '[MyPluginSolution]' (are you missing an assembly reference?)

原因是调用运行时编译剃须刀视图的 csc 编译器只能从 bin 文件夹和 GAC 获取 dll 引用。

我也尝试过使用this technique 预编译视图,但最后它给出了相同的结果,因为运行时坚持为预编译的剃刀视图编译一个包装器。

我当然可以将插件 dll 放到 /bin 文件夹中,但我的问题是:

有没有办法在非 bin(和非 GAC)文件夹中注册 dll,并将它们视为“一等公民”,以便剃刀视图可以使用它们?

【问题讨论】:

    标签: asp.net-mvc-3 plugins razor


    【解决方案1】:

    好的,使用this article找到了解决方案。

    首先我用 PreApplicationStartMethod 创建一个类。此方法扫描插件文件夹并将dll复制到AppDomain.DynamicDirectory。

    然后使用 BuildManager.AddReferencedAssembly 加载每个 dll。

    瞧,强类型的 Razor 视图编译得很漂亮。看这里的代码:

    [assembly: PreApplicationStartMethod(typeof(MySolution.PluginHandler.PluginActivator), "Initialize")]
    namespace MySolution.PluginHandler
    {
        public class PluginActivator
        {
            private static readonly DirectoryInfo PluginFolderInfo;
    
            static PluginActivator() {
                PluginFolderInfo = new DirectoryInfo(HostingEnvironment.MapPath("~/plugins"));
            }
    
            public static void Initialize() {
                CopyPluginDlls(PluginFolderInfo, AppDomain.CurrentDomain.DynamicDirectory);
                LoadPluginAssemblies(AppDomain.CurrentDomain.DynamicDirectory);
            }
    
            private static void CopyPluginDlls(DirectoryInfo sourceFolder, string destinationFolder)
            {
                foreach (var plug in sourceFolder.GetFiles("*.dll", SearchOption.AllDirectories)) {
                    if (!File.Exists(Path.Combine(destinationFolder, plug.Name))) {
                        File.Copy(plug.FullName, Path.Combine(destinationFolder, plug.Name), false);
                    }
                }
            }
    
            private static void LoadPluginAssemblies(string dynamicDirectory)
            {
                foreach (var plug in Directory.GetFiles(dynamicDirectory, "*.dll", SearchOption.AllDirectories)) {
                    Assembly assembly = Assembly.Load(AssemblyName.GetAssemblyName(plug));
                    BuildManager.AddReferencedAssembly(assembly);
                }
            }
        }
    }
    

    我希望这可以帮助其他想要使用这些新技术创建干净的插件框架的程序员。

    【讨论】:

    • 不把插件放到bin目录的原因是你不想重启应用吗?此解决方案仅在应用启动时加载插件 (BuildManager.AddReferencedAssembly) - 是否可以在 dynamicDirectory 中动态引用程序集?
    • 原因是这个解决方案可能有大量的插件,每个插件都有 3-5 个 dll。而且由于您不能将它们放入 /bin 下的子文件夹中,因此首选的解决方案是为此使用另一个文件夹。
    【解决方案2】:

    David Ebbo 最近发表了一篇关于将 Razor 视图预编译到程序集中的博客。您可以查看帖子here。

    您应该能够避免直接通过动态加载程序集来注册程序集(我通常会为此使用我的 IoC 容器),然后为每个插件程序集调用 BuildManager.AddReferencedAssembly。

    【讨论】:

    • 谢谢本。但在他的案例中,就像在 Chris van de Steeg 的案例中一样,主机应用程序直接引用了插件程序集,因此不幸的是它并没有解决我的问题。
    • 我已经更新了我的答案,但请注意这都是“理论上的”:) - 更多细节haacked.com/archive/2010/05/16/…
    • 嗨,Ben,您的最新编辑为我指明了正确的方向。解决方案是包含一个 pre-Application_Start 方法,该方法将所有插件 dll 复制到 AppDomain.DynamicDirectory,然后调用 BuildManager.AddReferencedAssembly()。本文展示了如何在完全信任和中等信任下执行此操作:shazwazza.com/post/…。我会自己在这里发布答案。
    【解决方案3】:

    查看 MEF

    您也可以使用 Windsor Installers 执行此操作 - Mike Hadlow 对此非常擅长:http://mikehadlow.blogspot.com/2010/10/experimental-aspnet-mvc-add-ins-updated.html

    【讨论】:

      【解决方案4】:

      请查看 NOPCommerce 源代码。它有基于Shannon 工作的不错的插件框架。

      【讨论】:

        【解决方案5】:

        您还可以在 MVC3 和 4 中使用“区域”功能,您可以创建一个不错的插件系统。它在自己的程序集中分离了处理插件的模型、视图和控制器。

        【讨论】:

          【解决方案6】:

          http://www.adverseconditionals.com/2011/07/portable-aspnet-code-using.html您可能会觉得这很有帮助

          我已经开始创建两个项目

          我的图书馆 我的图书馆.模板

          并将视图作为 .Templates 中的内容,并作为链接添加并设置为 MyLibrary 中的 EmbeddedResource。想要覆盖视图的人可以安装 .Templates 项目。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2022-07-28
            • 1970-01-01
            • 2011-06-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多