在开发一个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帮助你跟好的理解。