ASP.NET MVC 出来这么久了, 心中却又很多的疑惑: 为什么所有的 View 都要放在 Views 目录下? 为什么 Shared 文件夹下面的页面可以被共享? 为什么 Page 既可以是 *.cshtml, 也可以是 *.aspx?
其实上面的几个问题归结起来都是视图引擎的功效.
在传统的 ASP.NET 中, 可能还没有 ViewEngine 的概念. 因为在 web From 里面, 实现 Page 实现了 IHttpHanlder 的接口, 所以 Page 既是响应的处理类, 也是视图的渲染类. 在 ASP.NET MVC 中, 视图的概念被抽象了出来, 试图引擎的概念也被抽象成了一个接口.
首先来看一下 IViewEngine 接口的定义
- namespace System.Web.Mvc
- {
- public interface IViewEngine
- {
- ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache);
- ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache);
- void ReleaseView(ControllerContext controllerContext, IView view);
- }
- }
总共 3 个函数, 总结起来大概就是两个功能: Find & Release.
默认情况下, ASP.NET MVC 提供了两个视图引擎: WebFormViewEngine 和 RazorViewEngine
- namespace System.Web.Mvc
- {
- public static class ViewEngines
- {
- private static readonly ViewEngineCollection _engines = new ViewEngineCollection
- {
- new WebFormViewEngine(),
- new RazorViewEngine(),
- };
- public static ViewEngineCollection Engines
- {
- get { return _engines; }
- }
- }
- }
这就是为什么 ASP.NET MVC 既支持 *.aspx, 又支持 *.cshtml 的原因了 (个人觉得如果已经确定要使用 RazorView 的话, 不如把 WebFormViewEngine 给移除, 可能对性能会有所帮助).
那为什么所有的视图都要放在 Views 目录下呢, 这个就要拜 RazorViewngines 所赐了.
下面是 RazorViewEngine 的构造函数:
- public RazorViewEngine(IViewPageActivator viewPageActivator)
- : base(viewPageActivator)
- {
- AreaViewLocationFormats = new[]
- {
- "~/Areas/{2}/Views/{1}/{0}.cshtml",
- "~/Areas/{2}/Views/{1}/{0}.vbhtml",
- "~/Areas/{2}/Views/Shared/{0}.cshtml",
- "~/Areas/{2}/Views/Shared/{0}.vbhtml"
- };
- AreaMasterLocationFormats = new[]
- {
- "~/Areas/{2}/Views/{1}/{0}.cshtml",
- "~/Areas/{2}/Views/{1}/{0}.vbhtml",
- "~/Areas/{2}/Views/Shared/{0}.cshtml",
- "~/Areas/{2}/Views/Shared/{0}.vbhtml"
- };
- AreaPartialViewLocationFormats = new[]
- {
- "~/Areas/{2}/Views/{1}/{0}.cshtml",
- "~/Areas/{2}/Views/{1}/{0}.vbhtml",
- "~/Areas/{2}/Views/Shared/{0}.cshtml",
- "~/Areas/{2}/Views/Shared/{0}.vbhtml"
- };
- ViewLocationFormats = new[]
- {
- "~/Views/{1}/{0}.cshtml",
- "~/Views/{1}/{0}.vbhtml",
- "~/Views/Shared/{0}.cshtml",
- "~/Views/Shared/{0}.vbhtml"
- };
- MasterLocationFormats = new[]
- {
- "~/Views/{1}/{0}.cshtml",
- "~/Views/{1}/{0}.vbhtml",
- "~/Views/Shared/{0}.cshtml",
- "~/Views/Shared/{0}.vbhtml"
- };
- PartialViewLocationFormats = new[]
- {
- "~/Views/{1}/{0}.cshtml",
- "~/Views/{1}/{0}.vbhtml",
- "~/Views/Shared/{0}.cshtml",
- "~/Views/Shared/{0}.vbhtml"
- };
- FileExtensions = new[]
- {
- "cshtml",
- "vbhtml",
- };
- }
所有的寻址路径都被格式化了, 是不是很眼熟呢, 关于这里为啥用数组而不用 List, 个人觉得, 数组的寻址效率要更高些, 遍历速度更快.
好了, 找了 "罪魁祸首", 就好好地调教一个, 让它乖乖听话, 小样让去哪就去哪里.
- /// <summary>
- /// razor 视图引擎扩展
- /// </summary>
- public class CustomerViewEngine : RazorViewEngine
- {
- /// <summary>
- /// 可以分开部署不同语种
- /// </summary>
- /// <param name="engineName"></param>
- public CustomerViewEngine(string engineName)
- {
- base.ViewLocationFormats = new[]
- {
- "~/Views" + engineName + "/{1}/{0}.cshtml",
- "~/Views" + engineName + "/Shared/{0}.cshtml"
- };
- base.PartialViewLocationFormats = new[]
- {
- "~/Views" + engineName + "/{1}/{0}.cshtml",
- "~/Views" + engineName + "/Shared/{0}.cshtml"
- };
- base.AreaViewLocationFormats = new[]
- {
- "~Areas/{2}/Views" + engineName + "/{1}/{0}.cshtml",
- "~Areas/{2}/Views" + engineName + "/Shared/{0}.cshtml"
- };
- base.AreaPartialViewLocationFormats = new[]
- {
- "~Areas/{2}/Views" + engineName + "/{1}/{0}.cshtml",
- "~Areas/{2}/Views" + engineName + "/Shared/{0}.cshtml"
- };
- }
- public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
- {
- this.SetEngine(controllerContext);
- return base.FindView(controllerContext, viewName, masterName, useCache);
- }
- public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
- {
- this.SetEngine(controllerContext);
- return base.FindPartialView(controllerContext, partialViewName, useCache);
- }
- /// <summary>
- /// 根据条件自行设置, 目前是 Chrome 浏览器就展示默认的
- /// 不是 Chrome 浏览器的话就展示 / Themes/Eleven 下的
- /// 可以直接测试是移动端还是 pc 端
- /// 然后写入 cookie
- /// </summary>
- private void SetEngine(ControllerContext controllerContext)
- {
- string engineName = "/Themes/Eleven";
- if (controllerContext.HttpContext.Request.UserAgent.IndexOf("Chrome/65")>= 0)
- {
- engineName = null;
- }
- //if (controllerContext.HttpContext.Request.IsMobile())// 检测是不是移动端
- //{
- // engineName = null;
- //}
- base.ViewLocationFormats = new[]
- {
- "~/Views" + engineName + "/{1}/{0}.cshtml",
- "~/Views" + engineName + "/Shared/{0}.cshtml"
- };
- base.PartialViewLocationFormats = new[]
- {
- "~/Views" + engineName + "/{1}/{0}.cshtml",
- "~/Views" + engineName + "/Shared/{0}.cshtml"
- };
- base.AreaViewLocationFormats = new[]
- {
- "~Areas/{2}/Views" + engineName + "/{1}/{0}.cshtml",
- "~Areas/{2}/Views" + engineName + "/Shared/{0}.cshtml"
- };
- base.AreaPartialViewLocationFormats = new[]
- {
- "~Areas/{2}/Views" + engineName + "/{1}/{0}.cshtml",
- "~Areas/{2}/Views" + engineName + "/Shared/{0}.cshtml"
- };
- }
接下去就很简单了, 只需要把原来的视图引擎清空, 加载自己的视图引擎就可以了
- protected void Application_Start()
- {
- AreaRegistration.RegisterAllAreas();
- ViewEngines.Engines.Clear();
- ViewEngines.Engines.Add(new CustomViewEngine());
- RegisterGlobalFilters(GlobalFilters.Filters);
- RegisterRoutes(RouteTable.Routes);
- }
来源: https://www.cnblogs.com/saodiseng2015/p/9742283.html