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 插件式开发的更多相关文章

  1. 零基础ASP.NET Core MVC插件式开发

    零基础ASP.NET Core MVC插件式开发 一个项目随着业务模块的不断增加,系统会越来越庞大.如果参与开发的人员越多,管理起来也难度也很大.面对这样的情况,首先想到的是模块化插件式开发,根据业务 ...

  2. MVC插件式开发平台

    ---恢复内容开始--- 经过DyOS.BraveOS1.0再到BraveOS2.0,系统现在已经开发了下载. 我们的目标是,网页版操作系统,可以在线安装更新软件,并提供二次开发平台,提供基础的逻辑和 ...

  3. 基于OSGI.NET的MVC插件式开发

    最近在研究OSGI.NET插件式开发框架.官方网站提供了一个基于OSGI.NET的插件仓库.下载官方的SDK包安装后VS项目模板会多出一组iOpenWorks项目模板.在学习过程中,发现通过iOpen ...

  4. .NET MVC 简单的插件式开发

    插件式开发的优势 1.提高软件的复用度 2.提高软件开发的并行性 3.缩短软件的研发周期.节约研发成本,带给程序开发人员更多的灵活性,产品在软件发布以后还可以添加新的插件和完善已有的功能. 4.方便软 ...

  5. 从零开始实现ASP.NET Core MVC的插件式开发(一) - 使用ApplicationPart动态加载控制器和视图

    标题:从零开始实现ASP.NET Core MVC的插件式开发(一) - 使用Application Part动态加载控制器和视图 作者:Lamond Lu 地址:http://www.cnblogs ...

  6. 从零开始实现ASP.NET Core MVC的插件式开发(二) - 如何创建项目模板

    标题:从零开始实现ASP.NET Core MVC的插件式开发(二) - 如何创建项目模板 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p/11155 ...

  7. 从零开始实现ASP.NET Core MVC的插件式开发(三) - 如何在运行时启用组件

    标题:从零开始实现ASP.NET Core MVC的插件式开发(三) - 如何在运行时启用组件 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p/112 ...

  8. 从零开始实现ASP.NET Core MVC的插件式开发(四) - 插件安装

    标题:从零开始实现ASP.NET Core MVC的插件式开发(四) - 插件安装 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p/11260750. ...

  9. 从零开始实现ASP.NET Core MVC的插件式开发(五) - 插件的删除和升级

    标题:从零开始实现ASP.NET Core MVC的插件式开发(五) - 使用AssemblyLoadContext实现插件的升级和删除 作者:Lamond Lu 地址:https://www.cnb ...

随机推荐

  1. MoveWindow and SetWindowPos

    转自:http://blog.sina.com.cn/s/blog_82c346de0100u7kq.html MoveWindow and SetWindowPos (2011-09-14 15:5 ...

  2. OC省字典的数组摘要集

    开放式党员 NSString *filePath = @"/Users/dlios/Downloads/area.txt"; 推断错误值 打印出来 NSError *error = ...

  3. Angular绑定数据时转义html标签

    AngularJs在绑定数据时默认会以文本的形式出现在页面上,比如我现在有这样一段代码 <div ng-controller="testCtrl">{{data}}&l ...

  4. 解决 TortoiseGit 诡异的 Bad file number 问题(转)

    问题描述 昨天,以及今天(2014-11-29),使用 TortoiseGit 时碰到了一个诡异的问题. 卸载,清理注册表,重装,重启,各种折腾以后,还是不能解决. 但是23.45分一过,突然灵光一闪 ...

  5. Linux了解进程的地址空间

    供Linux了解虚拟内存,非常好的引导了.原文链接:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=26683523&i ...

  6. ServiceStack.Redis——Redis于.net向上client解

    ServiceStack.Redis--Redis于.net向上client解 源代码和使用: https://github.com/ServiceStack/ServiceStack.Redis 样 ...

  7. MySQL中游标使用以及读取文本数据

    原文:MySQL中游标使用以及读取文本数据 前言 之前一直没有接触数据库的学习,只是本科时候修了一本数据库基本知识的课.当时只对C++感兴趣,天真的认为其它的课都没有用,数据库也是半懂不懂,胡乱就考试 ...

  8. ASP.NET MVC2.0 自定义filters

    今天大家共同学习下ASP.NET MVC2.0中自定义filters,这一节主要学习下ActionFilterAttribute, ActionFilterAttribute继承IActionFilt ...

  9. JS通用方法扩展

    /* * 系统中JS的扩展函数 * * */ // 清除两边的空格 String.prototype.trim = function() { returnthis.replace(/(^\s*)|(\ ...

  10. eclipse 组态xdebug

    1.打开浏览器打开phpinfo页面视图PHP版本号.TS(线程安全)版本NTS(非线程安全)版本.以及VC6版本号是VC9版本号 2.和上面版本号相应的xdebug:http://xdebug.or ...