MVC 插件式开发

MVC 插件式开发

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

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

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

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

现在看一下主要代码。

MVC 插件式开发_第3张图片

复制代码
 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)