MVC 插件式开发

在开发一个OA系统是,我们可能遇到 A模块. B模块 .C模块,这也模块组成一个完整的系统,买给客服。
现在又有一个客服要我们做一个OA系统,唉我们发现,跟上一个OA系统差不多,但没有C模块。怎么办?

修改源码,系统简单还好,但是一系统复杂到一定程度,修改源码改这改这就像重写了!

怎么办,MVC插件式开发帮你解决问题,先看演示,再看代码。
MVC 插件式开发-LMLPHP
CCAV.WebSite 是主站,引用 CCAV.Modules.Category
 CCAV.Modules.Category 就像当于一个模块,具体看演示。

MVC 插件式开发-LMLPHP
通过主站可以访问到CCAV.Modules.Category 的控制器,如果 主站移除 对 CCAV.Modules.Category引用 将访问不到  CCAV.Modules.Category 你的控制器。
这样刚才的问题就解决了!

现在看一下主要代码。

MVC 插件式开发-LMLPHP

MVC 插件式开发-LMLPHP
 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);
}
}
MVC 插件式开发-LMLPHP
VirtualPathConfig.Register();/ 注册虚拟路径提供者以实现模块化拆分
ViewEngines.Engines.Clear(); 移除全部视图引擎.....
ViewEngines.Engines.Add(new RazorViewEngineExpand()); 假如自己的视图引擎
MVC 插件式开发-LMLPHP
  /// <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);
}
}
MVC 插件式开发-LMLPHP
   HostingEnvironment.RegisterVirtualPathProvider(GriffinVirtualPathProvider.Current);注册新的虚拟路径提供者:
StaticFileProvider  提供对图片、脚本、样式表等静态文件的访问
ViewFileProvider   视图文件提供
StaticFileProvider  ViewFileProvider  继承于 IViewFileProvider 看他们的内部实现
MVC 插件式开发-LMLPHP
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);
}
}
}
MVC 插件式开发-LMLPHP

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

MVC 插件式开发-LMLPHP
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
}
}
MVC 插件式开发-LMLPHP

然后再获取缓存

MVC 插件式开发-LMLPHP
    /// <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);
}
MVC 插件式开发-LMLPHP

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

MVC 插件式开发-LMLPHP
  /// <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);
}
MVC 插件式开发-LMLPHP

就是这样一个流程..................................

资料: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帮助你跟好的理解。

05-08 15:18