千家信息网

ASP.NET中MVC引擎开发插系统的示例分析

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,小编给大家分享一下ASP.NET中MVC引擎开发插系统的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、前言我心
千家信息网最后更新 2026年11月02日ASP.NET中MVC引擎开发插系统的示例分析

小编给大家分享一下ASP.NET中MVC引擎开发插系统的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

一、前言

我心中的插件系统应该是像Nop那样(更牛逼的如Orchard,OSGI.NET),每个插件模块不只是一堆实现了某个业务接口的dll,然后采用反射或IOC技术来调用,而是一个完整的mvc小应用,我可以在后台控制插件的安装和禁用,目录结构如下:

生成后放在站点根目录下的Plugins文件夹中,每个插件有一个子文件夹

Plugins/Sms.AliYun/

Plugins/Sms.ManDao/

我是一个有强迫症的的懒人,我不想将生成的dll文件拷贝到bin目录。

二、要解决的问题

1.asp.net引擎默认只会加载"bin"文件夹中的dll,而我们想要的插件文件则是分散在Plugins目录下的各个子目录中。

2.视图中使用了模型时如何处理?默认情况下RazorViewEngine使用BuildManager将视图编译成动态程序集,然后使用Activator.CreateInstance实例化新编译的对象,而使用插件dll时,当前的AppDomain不知道如何解析这种引用了模型的视图,因为它不存在于"bin"或GAC中。更糟糕的是,不会收到任何错误消息,告诉您为什么它不工作,或者问题在哪。相反,他会告诉你,从View目录中找不到文件。

3.某个插件正挂在站点下运行着,直接覆盖插件的dll,会告诉你当前dll正在使用,不能被覆盖。

4.视图文件不放站点的View目录中,该如何加载。

三.Net 4.0让这一切变成可能

Net4.0有一个新特性是在应用程序初始化之前执行代码的能力(PreApplicationStartMethodAttribute),这个特性使得应用程序在Application_Star前可以做一些工作,例如我们可以在应用启动之前告知我们的mvc插件系统的dll放在哪,做预加载处理等。关于.net的几个新特性,有歪果仁写得有博客来介绍,点我。,关于PreApplicationStartMethodAttribute,有博友已经写过了,点我。 Abp的启动模块应该也是使用PreApplicationStartMethodAttribute这个特性原理来实现的,具体是不是这样还没看。

四、解决方案

1.修改主站点web.config目录,让运行时除了加载bin目录中的文件,还可以从其它目录加载

      

2.开发一个简易的插件管理类,这个类的作用就是在Application_Start之前就把Plugins各子目录中的dll拷贝到第1步指定的文件夹中,为了让demo尽可能简单,没有对重复的dll进行检测(比如插件中引用了ef程序集,主站点也引用了,在站点bin目录中已经存在ef的dll了,就没必要再把插件中的dll拷贝到上面设置的动态程序集目录中)

using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Reflection;using System.Text;using System.Threading.Tasks;using System.Web;using System.Web.Compilation;using System.Web.Hosting;[assembly: PreApplicationStartMethod(typeof(Plugins.Core.PreApplicationInit), "Initialize")]namespace Plugins.Core{ public class PreApplicationInit {  static PreApplicationInit()  {   PluginFolder = new DirectoryInfo(HostingEnvironment.MapPath("~/plugins"));   ShadowCopyFolder = new DirectoryInfo(HostingEnvironment.MapPath("~/plugins/temp"));  }  ///   /// 插件所在目录信息  ///   private static readonly DirectoryInfo PluginFolder;  ///   /// 程序应行时指定的dll目录  ///   private static readonly DirectoryInfo ShadowCopyFolder;  public static void Initialize()  {   Directory.CreateDirectory(ShadowCopyFolder.FullName);   //清空插件dll运行目录中的文件   foreach (var f in ShadowCopyFolder.GetFiles("*.dll", SearchOption.AllDirectories))   {    f.Delete();   }   foreach (var plug in PluginFolder.GetFiles("*.dll", SearchOption.AllDirectories).Where(i=>i.Directory.Parent.Name== "plugins"))   {    File.Copy(plug.FullName, Path.Combine(ShadowCopyFolder.FullName, plug.Name), true);   }   foreach (var a in    ShadowCopyFolder    .GetFiles("*.dll", SearchOption.AllDirectories)    .Select(x => AssemblyName.GetAssemblyName(x.FullName))    .Select(x => Assembly.Load(x.FullName)))   {    BuildManager.AddReferencedAssembly(a);   }  } }}

3.如何让View引擎找到我们的视图呢?答案是重写RazorViewEngine的方法,我采用了约定大于配置的方式(假设我们的插件项目命名空间为Plugins.Apps.Sms,那么默认的控制器命名空间为Plugins.Apps.Sms.Controllers,插件生成后的文件夹必须为/Plugins/Plugins.Apps.Sms/),通过分析当前控制器就可以知道当前插件的View目录位置

using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using System.Web;using System.Web.Mvc;using System.Web.WebPages.Razor;namespace Plugins.Web{ public class CustomerViewEngine : RazorViewEngine {  ///   /// 定义视图页所在地址。  ///   private string[] _viewLocationFormats = new[]  {   "~/Views/Parts/{0}.cshtml",   "~/Plugins/{pluginFolder}/Views/{1}/{0}.cshtml",   "~/Plugins/{pluginFolder}/Views/Shared/{0}.cshtml",   "~/Views/{1}/{0}.cshtml",   "~/Views/Shared/{0}.cshtml",  };  public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)  {   string ns = controllerContext.Controller.GetType().Namespace;   string controller = controllerContext.Controller.GetType().Name.Replace("Controller", "");   //说明是插件中的控制器,View目录需要单独处理   if (ns.ToLower().Contains("plugins"))   {    var pluginsFolder = ns.ToLower().Replace(".controllers", "");    ViewLocationFormats = ReplacePlaceholder(pluginsFolder);   }   return base.FindView(controllerContext, viewName, masterName, useCache);  }  ///   /// 替换pluginFolder占位符  ///   ///   private string[] ReplacePlaceholder(string folderName)  {   string[] tempArray = new string[_viewLocationFormats.Length];   if (_viewLocationFormats != null)   {    for (int i = 0; i < _viewLocationFormats.Length; i++)    {     tempArray[i] = _viewLocationFormats[i].Replace("{pluginFolder}", folderName);    }   }   return tempArray;  } }}

然后在主站点的Global.asax中将Razor引擎指定为我们重写过的

4.开始制作一个插件目录,跟我们平时建立的MVC项目并没有太大区别,只是发布时需要做一些设置。

.生成路径要按照第3条的约定来写,不然会找不到视图文件

.View目录下的web.config和.cshtml文件要复制到生成目录(在文件中点右键)

3.设置引用项目中的生成属性,主程序下面已经有了的就把"复制到输出目录"设置为无,要不然拷贝到动态bin目录时会出错,可以对第2步中的那个类改造一下,加入文件比较功能,bin目录中没有的,才拷贝到动态bin目录中。

4.生成后的目录结构如下:

5.跑一下,一切正常,插件中的控制器工作正常,视图中引用了Model也没问题

以上是"ASP.NET中MVC引擎开发插系统的示例分析"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

目录 插件 文件 视图 生成 程序 引擎 拷贝 文件夹 控制 系统 动态 控制器 特性 站点 应用 分析 开发 主站点 篇文章 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技资迅 狮子座互联网科技 融贸通互联网科技 科技互联网创业计划书 多迪互联网科技有限公司 互联网科技创新企业排名 广西拼得多互联网科技有限公司 创业天下互联网科技有限公司 常德市电业局互联网科技部 宁夏众和广鑫互联网科技有限公司 昭通互联网科技选哪家 洛阳共同富裕互联网科技有限公司 互联网金融科技名词解释 电子商务与互联网科技的关系 图游互联网科技 济南小医互联网科技有限公司招聘 互联网高科技行业有哪些企业 银川新华互联网科技学校原画 宁波允成互联网科技有限公司 高科技和互联网的现代国家 互联网络科技 有格互联网科技 互联网佳科技有限公司 互联网科技战争 狮子座互联网科技 互联网金融监管科技 温州喔噻互联网科技有限公司 顶级互联网科技成果有哪些 天津腾达互联网科技有限公司 求路客互联网科技电话
0