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

las*_*hou 13 plugins razor asp.net-mvc-3

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

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

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

我也尝试使用这种技术预编译视图,但最后它给出了相同的结果,因为运行时坚持为预编译的剃刀视图编译包装器.

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

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

las*_*hou 14

好的,使用这篇文章找到了解决方案.

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

然后使用加载这些dll中的每一个BuildManager.AddReferencedAssembly.

而且,强烈类型的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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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