一个带有ASP.NET MVC3和嵌入式Razor视图的插件框架

时间:2011-06-24 09:23:03

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

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

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

  • 每个插件都有自己的模型,控制器和视图。视图是嵌入式资源,控制器派生自PluginController类
  • 插件具有对定义PluginController基类
  • 的共享类库的依赖性引用
  • 托管插件的“shell”Web应用程序不得在设计时保留对任何插件的引用,因为它在设计时不知道它有哪些插件。
  • 插件dll被删除在shell应用程序的一个文件夹中,不是/ bin文件夹
  • shell负责:
    1. 发现插件(使用反射)
    2. 注册所有控制器(我正在使用Spring.Net)
    3. 创建到控制器的路由
    4. 通过自定义VirtualPathProvider
    5. 提供剃刀文件(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,并将它们视为“一等公民”,以便剃刀视图可以使用它们? < / p>

6 个答案:

答案 0 :(得分:14)

好的,使用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);
            }
        }
    }
}

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

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

查看MEF

你也可以和温莎安装人员一起做这件事 - 迈克哈德洛对此很好:http://mikehadlow.blogspot.com/2010/10/experimental-aspnet-mvc-add-ins-updated.html

答案 3 :(得分:1)

请查看NOPCommerce源代码。它有一个很好的插件框架,基于Shannon的工作。

答案 4 :(得分:1)

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

答案 5 :(得分:0)

您可能会发现这有用http://www.adverseconditionals.com/2011/07/portable-aspnet-code-using.html

我已经开始创建两个项目

在MyLibrary MyLibrary.Templates

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