Asp.net mvc 3 带有ASP.NET MVC3和嵌入式Razor视图的插件框架

Asp.net mvc 3 带有ASP.NET MVC3和嵌入式Razor视图的插件框架,asp.net-mvc-3,plugins,razor,Asp.net Mvc 3,Plugins,Razor,我正在使用Razor视图为ASP.NET MVC3设计一个插件框架,但在让嵌入式视图正常工作时遇到了一个问题 插件框架旨在具备以下功能: 每个插件都有自己的模型、控制器和视图。视图是嵌入式资源,控制器派生自PlugInControl类 插件具有对定义插件基类的共享类库的依赖引用 托管插件的“shell”web应用程序在设计时不得持有对任何插件的引用,因为它在设计时不知道自己拥有哪些插件 插件dll被放入shell应用程序的文件夹中,该文件夹不是/bin文件夹 壳牌负责: 发现插件(使用反射)

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

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

  • 每个插件都有自己的模型、控制器和视图。视图是嵌入式资源,控制器派生自PlugInControl类
  • 插件具有对定义插件基类的共享类库的依赖引用
  • 托管插件的“shell”web应用程序在设计时不得持有对任何插件的引用,因为它在设计时不知道自己拥有哪些插件
  • 插件dll被放入shell应用程序的文件夹中,该文件夹不是/bin文件夹
  • 壳牌负责:
  • 发现插件(使用反射)
  • 注册所有控制器(我正在为此使用Spring.Net)
  • 创建到控制器的路由
  • 通过自定义VirtualPathProvider为razor文件(cshtml)提供服务
现在一切正常,除非嵌入视图引用插件dll中的类型。然后我得到了一个臭名昭著的错误(名字被省略了):

命名空间“[MyPluginSolution]”中不存在类型或命名空间名称“[Plugins]”(是否缺少程序集引用?)

原因是在运行时调用csc编译器编译razor视图时,它只从bin文件夹和GAC中获取dll引用

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

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


是否有办法在非bin(和非GAC)文件夹中注册DLL,并将其视为“头等公民”,以便razor视图可以使用它们?David Ebbo最近在博客中谈到将razor视图预编译为程序集。你可以查看帖子

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

签出MEF


您也可以使用Windsor安装程序执行此操作-Mike Hadlow在这方面做了一个很好的尝试:

好的,解决方案是使用

首先,我用一个
预应用程序启动方法创建一个类。此方法扫描插件文件夹并将DLL复制到
AppDomain.DynamicDirectory

然后使用
BuildManager.addReferenceAssembly
加载每个dll

瞧,强类型Razor视图编译得非常漂亮。请参见此处的代码:

[程序集:预应用程序启动方法(typeof(MySolution.PluginHandler.PluginActivator),“初始化”)]
命名空间MySolution.PluginHandler
{
公共类插件
{
私有静态只读目录信息PluginFolderInfo;
静态插入器(){
PluginFolderInfo=newdirectoryinfo(HostingEnvironment.MapPath(“~/plugins”);
}
公共静态void Initialize(){
CopyPluginDlls(PluginFolderInfo、AppDomain.CurrentDomain.DynamicDirectory);
LoadPluginAssembly(AppDomain.CurrentDomain.DynamicDirectory);
}
私有静态void copyplugindells(DirectoryInfo sourceFolder、string destinationFolder)
{
foreach(sourceFolder.GetFiles(“*.dll”,SearchOption.AllDirectories)中的var插件){
如果(!File.Exists(Path.Combine(destinationFolder,plug.Name))){
File.Copy(plug.FullName,Path.Combine(destinationFolder,plug.Name),false);
}
}
}
私有静态void LoadPluginAssemblies(字符串动态目录)
{
foreach(var插件目录.GetFiles(dynamicDirectory,“*.dll”,SearchOption.AllDirectories)){
Assembly=Assembly.Load(AssemblyName.GetAssemblyName(plug));
BuildManager.addReferenceAssembly(程序集);
}
}
}
}

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

您可能会发现这很有帮助

我已经开始创建两个项目

我的图书馆 MyLibrary.Templates


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

请查看NOPCommerce源代码。它有一个很好的插件框架

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

谢谢Ben。但在他的例子中,就像Chris van de Steeg的例子一样,主机应用程序直接引用插件程序集,因此不幸的是,它没有解决我的问题。我更新了我的答案,但请注意这都是“理论上的”)——更多细节嗨,Ben,你最近的编辑为我指明了正确的方向。解决方案是包含一个预应用程序启动方法,该方法将所有插件DLL复制到AppDomain.DynamicDirectory,然后调用BuildManager.addReferenceAssembly()。本文介绍了如何在完全信任和中等信任中执行此操作:。我将自己在这里发布答案。不在bin目录中放置插件的原因是你不想重新启动应用程序吗?此解决方案仅在应用程序启动时加载插件(BuildManager.AddReferencedAssembly)-是否可以在dynamicDirectory中动态引用程序集?原因是