MVC 插件式开发
MVC 插件式开发
在开发一个OA系统是,我们可能遇到 A模块. B模块 .C模块,这也模块组成一个完整的系统,买给客服。
现在又有一个客服要我们做一个OA系统,唉我们发现,跟上一个OA系统差不多,但没有C模块。怎么办?
修改源码,系统简单还好,但是一系统复杂到一定程度,修改源码改这改这就像重写了!
怎么办,MVC插件式开发帮你解决问题,先看演示,再看代码。
CCAV.WebSite 是主站,引用 CCAV.Modules.Category
CCAV.Modules.Category 就像当于一个模块,具体看演示。

通过主站可以访问到CCAV.Modules.Category 的控制器,如果 主站移除 对 CCAV.Modules.Category引用 将访问不到 CCAV.Modules.Category 你的控制器。
这样刚才的问题就解决了!
现在看一下主要代码。


public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
VirtualPathConfig.Register();
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new RazorViewEngineExpand()); AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
}

VirtualPathConfig.Register();/ 注册虚拟路径提供者以实现模块化拆分
ViewEngines.Engines.Clear(); 移除全部视图引擎.....
ViewEngines.Engines.Add(new RazorViewEngineExpand()); 假如自己的视图引擎

/// <summary>
/// 虚拟路径提供者配置
/// </summary>
public class VirtualPathConfig
{
/// <summary>
/// 注册虚拟路径提供者以实现模块化拆分
/// </summary>
public static void Register()
{
GriffinVirtualPathProvider.Current.Add(new StaticFileProvider(new PluginFileLocator()));
GriffinVirtualPathProvider.Current.Add(new ViewFileProvider(new PluginFileLocator(), new ExternalViewFixer())); HostingEnvironment.RegisterVirtualPathProvider(GriffinVirtualPathProvider.Current);
}
}

HostingEnvironment.RegisterVirtualPathProvider(GriffinVirtualPathProvider.Current);注册新的虚拟路径提供者:
StaticFileProvider 提供对图片、脚本、样式表等静态文件的访问
ViewFileProvider 视图文件提供
StaticFileProvider ViewFileProvider 继承于 IViewFileProvider 看他们的内部实现

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web.Caching;
using System.Web.Hosting; namespace ItCast.Foundation.Hosting
{
/// <summary>
/// 自定义的虚拟路径提供者。
/// </summary>
public class GriffinVirtualPathProvider : VirtualPathProvider
{
private static readonly GriffinVirtualPathProvider Instance = new GriffinVirtualPathProvider();
private readonly List<IViewFileProvider> fileProviders = new List<IViewFileProvider>(); /// <summary>
/// 初始化 GriffinVirtualPathProvider 类的新实例。
/// </summary>
private GriffinVirtualPathProvider()
{
} /// <summary>
/// 获得实例。
/// </summary>
public static GriffinVirtualPathProvider Current
{
get
{
return Instance;
}
} /// <summary>
/// 添加一个新的文件提供者。
/// </summary>
/// <param name="fileProvider">文件提供者。</param>
public void Add(IViewFileProvider fileProvider)
{
if (fileProvider == null)
{
throw new ArgumentNullException("fileProvider");
} this.fileProviders.Add(fileProvider);
} /// <summary>
/// 获取一个值,该值指示文件是否存在于虚拟文件系统中。
/// </summary>
/// <returns>
/// 如果该文件存在于虚拟文件系统中,则为 true;否则为 false。
/// </returns>
/// <param name="virtualPath">虚拟文件的路径。</param>
public override bool FileExists(string virtualPath)
{
foreach (var provider in this.fileProviders)
{
if (provider.FileExists(virtualPath))
{
return true;
}
} return base.FileExists(virtualPath);
} /// <summary>
/// 基于指定的虚拟路径创建一个缓存依赖项。
/// </summary>
/// <param name="virtualPath">主虚拟资源的路径。</param>
/// <param name="virtualPathDependencies">一个路径数组,路径指向主要虚拟资源需要的其他资源。</param>
/// <param name="utcStart">虚拟资源被读取的 UTC 时间。</param>
/// <returns>
/// 指定虚拟资源的 <see cref="T:System.Web.Caching.CacheDependency"/> 对象。
/// </returns>
public override CacheDependency GetCacheDependency(
string virtualPath,
IEnumerable virtualPathDependencies,
DateTime utcStart)
{
foreach (var provider in this.fileProviders)
{
var result = provider.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
if (result is NoCache)
{
return null;
} if (result != null)
{
return result;
}
} return base.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
} /// <summary>
/// 返回一个用于指定虚拟路径的缓存键。
/// </summary>
/// <param name="virtualPath">虚拟资源的路径。</param>
/// <returns>
/// 所指定虚拟资源的缓存键。
/// </returns>
public override string GetCacheKey(string virtualPath)
{
foreach (
var result in
this.fileProviders.Select(provider => provider.GetCacheKey(virtualPath)).Where(result => result != null))
{
return result;
} return base.GetCacheKey(virtualPath);
} /// <summary>
/// 从虚拟文件系统中获取一个虚拟文件。
/// </summary>
/// <param name="virtualPath">虚拟文件的路径。</param>
/// <returns>
/// <see cref="T:System.Web.Hosting.VirtualFile"/> 类的子代,该子代表示虚拟文件系统中的一个文件。
/// </returns>
public override VirtualFile GetFile(string virtualPath)
{
foreach (var provider in this.fileProviders)
{
var file = provider.GetFile(virtualPath);
if (file != null)
{
return file;
}
} return base.GetFile(virtualPath);
} /// <summary>
/// 返回指定虚拟路径的哈希值。
/// </summary>
/// <param name="virtualPath">主虚拟资源的路径。</param>
/// <param name="virtualPathDependencies">一个路径数组,所包含的路径指向主要虚拟资源需要的其他虚拟资源。</param>
/// <returns>
/// 指定虚拟路径的哈希值。
/// </returns>
public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies)
{
foreach (
var result in
this.fileProviders.Select(provider => provider.GetFileHash(virtualPath, virtualPathDependencies)).Where(
result => result != null))
{
return result;
} return base.GetFileHash(virtualPath, virtualPathDependencies);
}
}
}

一开始进入这个方法 FileExists 判断文件是否存在,春在这位true

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Hosting; namespace ItCast.Foundation.Hosting
{
/// <summary>
/// Locator which loads views using the project structure to enable runtime view edits.
/// </summary>
/// <remarks>
/// Works as long as you have used the structure which is described in the namespace documentation.
/// </remarks>
public class PluginFileLocator : IViewFileLocator
{
private readonly string basePath;
private IEnumerable<string> allowedFileExtensions; /// <summary>
/// Initializes a new instance of the <see cref="PluginFileLocator"/> class.
/// </summary>
public PluginFileLocator()
{
this.basePath = Path.GetFullPath(HostingEnvironment.MapPath("~") + @"..");
} #region IViewFileLocator Members /// <summary>
/// Get full path to a file
/// </summary>
/// <param name="uri">Requested uri</param>
/// ~/Admin/Content/themes/Blog/Site.css
/// ~/Admin/Scripts/Blog/BlogAjax.js
/// ~/Admin/Views/Blog/Home/Index.cshtml
/// ~/Content/themes/Blog/Site.css
/// ~/Scripts/Blog/BlogAjax.js
/// ~/Views/Blog/Home/Index.cshtml
/// <returns>
/// Full disk path if found; otherwise <c>null</c>.
/// </returns>
public string GetFullPath(string uri)
{
var pathConfigs = PluginPathConfig.GetConfigs();
var fixedUri = uri;
if (fixedUri.StartsWith("~"))
{
fixedUri = VirtualPathUtility.ToAbsolute(uri);
} var path = string.Empty;
foreach (var pattern in pathConfigs.Keys)
{
var regex = new Regex(pattern, RegexOptions.IgnoreCase);
var match = regex.Match(fixedUri);
if (match.Length > 0)
{
path = Regex.Replace(fixedUri, pattern, pathConfigs[pattern], RegexOptions.IgnoreCase);
path = string.Format("{0}\\{1}", this.basePath, path.Replace('/', '\\'));
break;
}
} if (!this.IsFileAllowed(uri))
{
return null;
} if (File.Exists(path))
{
return path;
} return null;
} /// <summary>
/// Set extensions that are allowed to be scanned.
/// </summary>
/// <param name="fileExtensions">File extensions without the dot.</param>
public void SetAllowedExtensions(IEnumerable<string> fileExtensions)
{
this.allowedFileExtensions = fileExtensions;
} /// <summary>
/// determins if the found embedded file might be mapped and provided.
/// </summary>
/// <param name="fullPath">Full path to the file</param>
/// <returns><c>true</c> if the file is allowed; otherwise <c>false</c>.</returns>
protected virtual bool IsFileAllowed(string fullPath)
{
if (fullPath == null)
{
throw new ArgumentNullException("fullPath");
} var extension = fullPath.Substring(fullPath.LastIndexOf('.') + 1);
return this.allowedFileExtensions.Any(x => x == extension.ToLower());
} #endregion
}
}

然后再获取缓存

/// <summary>
/// 返回一个用于指定虚拟路径的缓存键。
/// </summary>
/// <param name="virtualPath">虚拟资源的路径。</param>
/// <returns>
/// 所指定虚拟资源的缓存键。
/// </returns>
public override string GetCacheKey(string virtualPath)
{
foreach (
var result in
this.fileProviders.Select(provider => provider.GetCacheKey(virtualPath)).Where(result => result != null))
{
return result;
} return base.GetCacheKey(virtualPath);
}

缓存没找到,从虚拟文件系统中获取一个虚拟文件

/// <summary>
/// 从虚拟文件系统中获取一个虚拟文件。
/// </summary>
/// <param name="virtualPath">虚拟文件的路径。</param>
/// <returns>
/// <see cref="T:System.Web.Hosting.VirtualFile"/> 类的子代,该子代表示虚拟文件系统中的一个文件。
/// </returns>
public override VirtualFile GetFile(string virtualPath)
{
foreach (var provider in this.fileProviders)
{
var file = provider.GetFile(virtualPath);
if (file != null)
{
return file;
}
} return base.GetFile(virtualPath);
}

就是这样一个流程..................................
资料:http://msdn.microsoft.com/zh-cn/library/system.web.hosting.virtualpathprovider(VS.80).aspx
源码:http://pan.baidu.com/s/1pJsgaIf
你可以看这篇文章:http://www.cnblogs.com/liek/p/3898168.html帮助你跟好的理解。
MVC 插件式开发的更多相关文章
- 零基础ASP.NET Core MVC插件式开发
零基础ASP.NET Core MVC插件式开发 一个项目随着业务模块的不断增加,系统会越来越庞大.如果参与开发的人员越多,管理起来也难度也很大.面对这样的情况,首先想到的是模块化插件式开发,根据业务 ...
- MVC插件式开发平台
---恢复内容开始--- 经过DyOS.BraveOS1.0再到BraveOS2.0,系统现在已经开发了下载. 我们的目标是,网页版操作系统,可以在线安装更新软件,并提供二次开发平台,提供基础的逻辑和 ...
- 基于OSGI.NET的MVC插件式开发
最近在研究OSGI.NET插件式开发框架.官方网站提供了一个基于OSGI.NET的插件仓库.下载官方的SDK包安装后VS项目模板会多出一组iOpenWorks项目模板.在学习过程中,发现通过iOpen ...
- .NET MVC 简单的插件式开发
插件式开发的优势 1.提高软件的复用度 2.提高软件开发的并行性 3.缩短软件的研发周期.节约研发成本,带给程序开发人员更多的灵活性,产品在软件发布以后还可以添加新的插件和完善已有的功能. 4.方便软 ...
- 从零开始实现ASP.NET Core MVC的插件式开发(一) - 使用ApplicationPart动态加载控制器和视图
标题:从零开始实现ASP.NET Core MVC的插件式开发(一) - 使用Application Part动态加载控制器和视图 作者:Lamond Lu 地址:http://www.cnblogs ...
- 从零开始实现ASP.NET Core MVC的插件式开发(二) - 如何创建项目模板
标题:从零开始实现ASP.NET Core MVC的插件式开发(二) - 如何创建项目模板 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p/11155 ...
- 从零开始实现ASP.NET Core MVC的插件式开发(三) - 如何在运行时启用组件
标题:从零开始实现ASP.NET Core MVC的插件式开发(三) - 如何在运行时启用组件 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p/112 ...
- 从零开始实现ASP.NET Core MVC的插件式开发(四) - 插件安装
标题:从零开始实现ASP.NET Core MVC的插件式开发(四) - 插件安装 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p/11260750. ...
- 从零开始实现ASP.NET Core MVC的插件式开发(五) - 插件的删除和升级
标题:从零开始实现ASP.NET Core MVC的插件式开发(五) - 使用AssemblyLoadContext实现插件的升级和删除 作者:Lamond Lu 地址:https://www.cnb ...
随机推荐
- 文件类似的推理 -- 超级本征值(super feature)
基于内容的变长分块(CDC)技术,能够用来对文件进行变长分块.而后用来进行反复性检測,广泛用于去重系统中.后来又出现了对相似数据块进行delta压缩,进一步节省存储开销. 所以就须要一种高效 ...
- 怎么在android的XML文件里加入凝视
android的XML文件凝视一般採用 <!--凝视内容 -->的方式进行 在XML中,形如 <Button /> 的表示方式,当中&quo ...
- ScrollView 在嵌套 ViewPager 时出现的问题
1.在ViewPager 外面嵌套ScrollView 时导致ViewPager 中内容不显示,解决的办法是在ScrollView 标签下增加 android:fillViewport="t ...
- Android GPS获取当前经纬度坐标
APP中可能会遇到一种需求,就是将当前所在位置的坐标传到server上,今天我提供三种途径去获取经纬度坐标信息,第一种是通过Android API来实现,另外一种通过百度地图API来实现,第三种通过天 ...
- 微博API怎么爬取其它未授权用户的微博/怎么爬取指定用户公布的微博
获取某个用户最新发表的微博列表:http://open.weibo.com/wiki/2/statuses/user_timeline 原接口已经被封.很多人都在问怎么获取指定用户的微博,于是写这篇B ...
- E - Speed Limit(2.1.1)
E - Speed Limit(2.1.1) Time Limit:1000MS Memory Limit:30000KB 64bit IO Format:%I64d & %I ...
- HDU 4292Food(网络流的最大流量)
职务地址:HDU 4292 水题. 因为每一个人仅仅能有1份,所以须要拆点限制流量.建图方法为,建一源点与汇点.将食物与源点相连,权值为食物额数量,将饮料与汇点相连,权值为饮料数量..然后将人进行拆点 ...
- 为代码减负之<二>存储过程(SQL)
在上篇博客中介绍到了触发器的使用,而且当中也提到了触发器是个特殊的存储过程,那么什么是存储过程呢?他们 两个又究竟有什么差别呢? 事实上最基本的差别就是,触发器是当满足条件时系统自己主动运行的,而存储 ...
- SRM 587 Div II L3:ThreeColorabilityEasyy
题目来源:http://community.topcoder.com/stat?c=problem_statement&pm=12699 这道题目是第一次在比赛的时候做出来的,开始还想用bru ...
- sql server 汉字的长度
前几天改了人家程序中的一个小bug,就是输入时长度的校验问题.项目是.Net的,数据库是 sql server的.检查了一下,发现以前的人员把长度给控制小了,数据库中允许输入256的长度,而别人在as ...