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. Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装

    原文:Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装 Linux内核分析(一) 从本篇博文开始我将对linux内核进行学习和分析,整个过程必将十分艰辛,但我会坚持到底 ...

  2. 常见的FPGA内串行数据采样的方式

    总结下常见的对串行数据采样的三种方式: 1. 全采样存储方式: 采用过采样,用过采样时钟,用移位寄存器移位,把每次采样值都存起来.采用高速的过采样时钟运行. 然后等待触发条件,(就是找到数据的起始点条 ...

  3. EMVTag系列5《8E 持卡人验证方法(CVM)名单》

    L: var. up to 252 -R(需求):数据必须存在,在读应用数据过程中,终端不检查 依照优先顺序列出卡片应用支持的全部持卡人验证方法 注:一个应用中能够有多个CVM列表,比如一个用于国内交 ...

  4. 打印object对象

    在测试条件一般js时间,假定数据接口返回object对象. 假设不知道这个对象里面详细的属性就取值easy得到undefined. 哪么怎么知道一个object对象里面究竟是什么东西呢. 答案就是将其 ...

  5. projecteuler----&gt;problem=34----Digit factorials

    Problem 34 145 is a curious number, as 1! + 4! + 5! = 1 + 24 + 120 = 145. Find the sum of all number ...

  6. javascript权威指南(6) - 对象

    JavaScript对象可以从一个称为原型的对象继承属性,这种"原型式继承"(prototypal inheritance)是JavaScript的核心特征.除了字符串.数字.tr ...

  7. 【百度地图API】手机浏览器抓包工具及其使用方法

    原文:[百度地图API]手机浏览器抓包工具及其使用方法 摘要:为了测试地图API在手机浏览器上的性能,需要给手机浏览器设置代理.通过代理,我们可以在PC上获取到抓包数据.进而对性能做进一步分析. -- ...

  8. IBM即将倒闭,微软也从崩溃18个月

    IBM公司20发布2014在第三季度财报.其三阶季度净利润1800万美元,下跌99.6%. 可见IBM我已经危及. 技术专家sun收购崩溃,说明一些原因,自满技术公司可能已用完.. sun以前靠小型机 ...

  9. 深入struts2.0(五)--Dispatcher类

    1.1.1       serviceAction方法 在上个Filter方法中我们会看到例如以下代码: this.execute.executeAction(request, response, m ...

  10. UVa 11121 - Base -2

    题目:计算以-2为基数的数的表示. 分析:数论.写出不同位数能表示的数字区间就能够找到规律. 长度为1:[1,1]: 长度为2:[-2,-1]: 长度为3:[2,5]: 观察发现,区间长度增长为1,2 ...