定制属于你自己的ViewEngine(一套逻辑多套UI)

ASP.NET MVC出来这么久了,心中却又很多的疑惑:为什么所有的View都要放在Views目录下? 为什么Shared文件夹下面的页面可以被共享? 为什么Page既可以是*.cshtml,也可以是*.aspx? 

其实上面的几个问题归结起来都是视图引擎的功效。

在传统的ASP.NET中,可能还没有ViewEngine的概念。因为在Web From里面,实现Page实现了IHttpHanlder的接口,所以Page既是响应的处理类,也是视图的渲染类。在ASP.NET MVC中,视图的概念被抽象了出来,试图引擎的概念也被抽象成了一个接口。

首先来看一下IViewEngine接口的定义

1 namespace System.Web.Mvc
2 {
3     public interface IViewEngine
4     {
5         ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache);
6         ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache);
7         void ReleaseView(ControllerContext controllerContext, IView view);
8     }
9 }

总共3个函数,总结起来大概就是两个功能:Find & Release。

 

 

默认情况下,ASP.NET MVC提供了两个视图引擎:WebFormViewEngine和RazorViewEngine

 1 namespace System.Web.Mvc
 2 {
 3     public static class ViewEngines
 4     {
 5         private static readonly ViewEngineCollection _engines = new ViewEngineCollection
 6         {
 7             new WebFormViewEngine(),
 8             new RazorViewEngine(),
 9         };
10  
11         public static ViewEngineCollection Engines
12         {
13             get { return _engines; }
14         }
15     }
16 }

这就是为什么ASP.NET MVC既支持*.aspx,又支持*.cshtml的原因了(个人觉得如果已经确定要使用RazorView的话,不如把WebFormViewEngine给移除,可能对性能会有所帮助)。

 

那为什么所有的视图都要放在Views目录下呢,这个就要拜RazorViewngines所赐了。

下面是RazorViewEngine的构造函数:

 1         public RazorViewEngine(IViewPageActivator viewPageActivator)
 2             : base(viewPageActivator)
 3         {
 4             AreaViewLocationFormats = new[]
 5             {
 6                 "~/Areas/{2}/Views/{1}/{0}.cshtml",
 7                 "~/Areas/{2}/Views/{1}/{0}.vbhtml",
 8                 "~/Areas/{2}/Views/Shared/{0}.cshtml",
 9                 "~/Areas/{2}/Views/Shared/{0}.vbhtml"
10             };
11             AreaMasterLocationFormats = new[]
12             {
13                 "~/Areas/{2}/Views/{1}/{0}.cshtml",
14                 "~/Areas/{2}/Views/{1}/{0}.vbhtml",
15                 "~/Areas/{2}/Views/Shared/{0}.cshtml",
16                 "~/Areas/{2}/Views/Shared/{0}.vbhtml"
17             };
18             AreaPartialViewLocationFormats = new[]
19             {
20                 "~/Areas/{2}/Views/{1}/{0}.cshtml",
21                 "~/Areas/{2}/Views/{1}/{0}.vbhtml",
22                 "~/Areas/{2}/Views/Shared/{0}.cshtml",
23                 "~/Areas/{2}/Views/Shared/{0}.vbhtml"
24             };
25  
26             ViewLocationFormats = new[]
27             {
28                 "~/Views/{1}/{0}.cshtml",
29                 "~/Views/{1}/{0}.vbhtml",
30                 "~/Views/Shared/{0}.cshtml",
31                 "~/Views/Shared/{0}.vbhtml"
32             };
33             MasterLocationFormats = new[]
34             {
35                 "~/Views/{1}/{0}.cshtml",
36                 "~/Views/{1}/{0}.vbhtml",
37                 "~/Views/Shared/{0}.cshtml",
38                 "~/Views/Shared/{0}.vbhtml"
39             };
40             PartialViewLocationFormats = new[]
41             {
42                 "~/Views/{1}/{0}.cshtml",
43                 "~/Views/{1}/{0}.vbhtml",
44                 "~/Views/Shared/{0}.cshtml",
45                 "~/Views/Shared/{0}.vbhtml"
46             };
47  
48             FileExtensions = new[]
49             {
50                 "cshtml",
51                 "vbhtml",
52             };
53         }

所有的寻址路径都被格式化了,是不是很眼熟呢,关于这里为啥用数组而不用List,个人觉得,数组的寻址效率要更高些,遍历速度更快。

 

好了,找了“罪魁祸首”,就好好地调教一个,让它乖乖听话,小样让去哪就去哪里。

 

 1  /// <summary>
 2     /// razor视图引擎扩展
 3     /// </summary>
 4     public class CustomerViewEngine : RazorViewEngine
 5     {
 6         /// <summary>
 7         /// 可以分开部署不同语种
 8         /// </summary>
 9         /// <param name="engineName"></param>
10         public CustomerViewEngine(string engineName)
11         {
12             base.ViewLocationFormats = new[]
13                 {
14                     "~/Views" + engineName + "/{1}/{0}.cshtml",
15                     "~/Views" + engineName + "/Shared/{0}.cshtml"
16                 };
17 
18             base.PartialViewLocationFormats = new[]
19                 {
20                     "~/Views" + engineName + "/{1}/{0}.cshtml",
21                     "~/Views" + engineName + "/Shared/{0}.cshtml"
22                 };
23 
24             base.AreaViewLocationFormats = new[]
25                 {
26                     "~Areas/{2}/Views" + engineName + "/{1}/{0}.cshtml",
27                     "~Areas/{2}/Views" + engineName + "/Shared/{0}.cshtml"
28                 };
29 
30             base.AreaPartialViewLocationFormats = new[]
31                 {
32                     "~Areas/{2}/Views" + engineName + "/{1}/{0}.cshtml",
33                     "~Areas/{2}/Views" + engineName + "/Shared/{0}.cshtml"
34                 };
35         }
36 
37         public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
38         {
39             this.SetEngine(controllerContext);
40             return base.FindView(controllerContext, viewName, masterName, useCache);
41         }
42 
43         public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
44         {
45             this.SetEngine(controllerContext);
46             return base.FindPartialView(controllerContext, partialViewName, useCache);
47         }
48 
49         /// <summary>
50         /// 根据条件自行设置,目前是chrome浏览器就展示默认的
51         /// 不是chrome浏览器的话就展示/Themes/Eleven下的
52         /// 可以直接测试是移动端还是pc端
53         /// 然后写入cookie
54         /// </summary>
55         private void SetEngine(ControllerContext controllerContext)
56         {
57             string engineName = "/Themes/Eleven";
58             if (controllerContext.HttpContext.Request.UserAgent.IndexOf("Chrome/65") >= 0)
59             {
60                 engineName = null;
61             }
62 
63             //if (controllerContext.HttpContext.Request.IsMobile())//检测是不是移动端
64             //{
65             //    engineName = null;
66             //}
67 
68             base.ViewLocationFormats = new[]
69                {
70                     "~/Views" + engineName + "/{1}/{0}.cshtml",
71                     "~/Views" + engineName + "/Shared/{0}.cshtml"
72                 };
73 
74             base.PartialViewLocationFormats = new[]
75                 {
76                     "~/Views" + engineName + "/{1}/{0}.cshtml",
77                     "~/Views" + engineName + "/Shared/{0}.cshtml"
78                 };
79 
80             base.AreaViewLocationFormats = new[]
81                 {
82                     "~Areas/{2}/Views" + engineName + "/{1}/{0}.cshtml",
83                     "~Areas/{2}/Views" + engineName + "/Shared/{0}.cshtml"
84                 };
85 
86             base.AreaPartialViewLocationFormats = new[]
87                 {
88                     "~Areas/{2}/Views" + engineName + "/{1}/{0}.cshtml",
89                     "~Areas/{2}/Views" + engineName + "/Shared/{0}.cshtml"
90                 };
91         }

 

接下去就很简单了,只需要把原来的视图引擎清空,加载自己的视图引擎就可以了

 1         protected void Application_Start()
 2         {
 3             AreaRegistration.RegisterAllAreas();
 4  
 5             ViewEngines.Engines.Clear();
 6  
 7             ViewEngines.Engines.Add(new CustomViewEngine());
 8  
 9             RegisterGlobalFilters(GlobalFilters.Filters);
10             RegisterRoutes(RouteTable.Routes);
11         }

 

posted @ 2018-10-04 15:06  扫地僧2015  阅读(1351)  评论(2编辑  收藏  举报