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. android控件 下拉刷新pulltorefresh

    外国人写的下拉刷新控件,我把他下载下来放在网盘,有时候訪问不了github 支持各种控件下拉刷新 ListView.ViewPager.WevView.ExpandableListView.GridV ...

  2. 解决TD于ie10没有问题,

    .打开命令提示符下,输入 gpedit 回车打开组策略编辑器: .计算机配置-管理模版-全部设置-关闭数据运行保护,双击打开.选择已启用.关闭组策略浏览器. .命令提示符下输入gpupdate/for ...

  3. ReactJS入门二

    ReactJS入门学习二 ReactJS入门学习二 阅读目录 React的背景和基本原理 理解React.render() 什么是JSX? 为什么要使用JSX? JSX的语法 如何在JSX中如何使用事 ...

  4. Display Database Image using MS SQL Server 2008 Reporting Services

    原文 Display Database Image using MS SQL Server 2008 Reporting Services With the new release of MS SQL ...

  5. Linux访问Windows共享文件夹 (转)

    在开发Linux程序中,经常会使用Windows的编辑器进行编辑,这样还要拷贝到Linux服务器,如果有这种开发习惯的同学,可以使用这种方式进行开发. 当然除了这种方法之外,可以再Windows安装n ...

  6. Git & Github 一页简明笔记(转)main

    由于小组工程需要使用git&github的版本控制来协作,但我对其使用并不熟悉,特此写篇一页的笔记放在手边,备随时查阅. 使用方法:常用命令供随时查阅,其余内容供新手了解. 0. 常用命令一览 ...

  7. 大数据系列修炼-Scala课程03

    前言 今天上班看了很多关于前端js,jQuery.bootstrap.js以及springMVC看得迷迷糊糊的,毕竟以前很少去学习前端的技术,所有看得有点困,还好看得比较多,回家后也开始学习关于Sca ...

  8. 运行时间(Java版本)—转换毫秒到时分秒日期

    第一种方式: import java.util.Calendar; import java.util.TimeZone; public class Test { /** * 将毫秒转换为年月日时分秒 ...

  9. crawler_google工作原理

  10. oracle_有关表分区_查询

    <!--查询ORACLE分区表存在多少个分区-->  SELECT * FROM USER_TAB_PARTITIONS WHERE TABLE_NAME='TBL_PAGE';  < ...