ASP.NET MVC 4 视图页去哪里儿

简介:

这里特别感谢 swagon 提到了Displaymodeprovider,所以才有了本篇博客,也使我对【View的呈现】中寻找视图页的过程有了清晰的认识!

前戏

在MVC中,执行完Action之后,会返回一个ActionResult对象,之后再执行该对象的ExecuteResult方法,这也就是【View的呈现】的入口!

【View的呈现】包括了:根据模版去寻找请求的视图页、编译视图页、再执行视图页的内容。本篇就来介绍寻找视图页的详细过程,其中涉及到了MVC 4的一个新特性--“手机视图页”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public  abstract  class  ViewResultBase : ActionResult
{
     public  override  void  ExecuteResult(ControllerContext context)
     {
         if  (context ==  null )
         {
             throw  new  ArgumentNullException( "context" );
         }
         if  (String.IsNullOrEmpty(ViewName))
         {
             ViewName = context.RouteData.GetRequiredString( "action" );
         }
       ViewEngineResult result =  null ;
         if  (View ==  null )
         {
             //通过视图引擎去创建视图对象,并将视图对象和该视图相关的信息封装在ViewEngineResult对象中。
             result = FindView(context);
             View = result.View;
         }
 
         TextWriter writer = context.HttpContext.Response.Output;
         ViewContext viewContext =  new  ViewContext(context, View, ViewData, TempData, writer);
         View.Render(viewContext, writer);
 
         if  (result !=  null )
         {
             result.ViewEngine.ReleaseView(context, View);
         }
     }
}
 
public  class  ViewResult : ViewResultBase
{
     protected  override  ViewEngineResult FindView(ControllerContext context)
     {
         //寻找当前请求的视图页,如果能找到则创建视图对象。
         //遍历每个视图引擎(默认有两个WebFormEngine、RazorViewEngine),并执行每一个视图引擎的FindView方法。
         ViewEngineResult result = ViewEngineCollection.FindView(context, ViewName, MasterName);
         //如果创建了视图对象,即:指定路径中存在相匹配的视图页(.cshtml文件)。
         if  (result.View !=  null )
         {
             return  result;
         }
         //没有创建视图对象,即:指定路径中不存在相匹配的视图页(.cshtml文件)。
         StringBuilder locationsText =  new  StringBuilder();
         foreach  ( string  location  in  result.SearchedLocations)
         {
             locationsText.AppendLine();
             locationsText.Append(location);
         }
         throw  new  InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
                                                           MvcResources.Common_ViewNotFound, ViewName, locationsText));
     }
}

  ViewEngineResult result = ViewEngineCollection.FindView(context, ViewName, MasterName);则是遍历每个视图引擎(默认有两个WebFormEngine、RazorViewEngine),并执行每一个视图引擎的FindView方法。
注:在执行视图引擎的FindView方法时,先按照从缓存表中找是否存在请求的视图页,如果没有的话,再进行一次寻找!

 下面以RazorViewEngine为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public  abstract  class  VirtualPathProviderViewEngine : IViewEngine
{
     //useCache先是true,该方法返回的是null。则让useCache=false,再执行一遍。即:先通过缓存去找,如果没有找到的话,就正经的去找。
     public  virtual  ViewEngineResult FindView(ControllerContext controllerContext,  string  viewName,  string  masterName,  bool  useCache)
     {
         if  (controllerContext ==  null )
         {
             throw  new  ArgumentNullException( "controllerContext" );
         }
         if  (String.IsNullOrEmpty(viewName))
         {
             throw  new  ArgumentException(MvcResources.Common_NullOrEmpty,  "viewName" );
         }
 
         string [] viewLocationsSearched;
         string [] masterLocationsSearched;
 
         string  controllerName = controllerContext.RouteData.GetRequiredString( "controller" );
         //获取视图的路径,这里就是咱们本篇博文的内容的入口点!!!!!!!!!!!!!!!!!!!
         //ViewLocationFormats、AreaViewLocationFormats定义在派生类RazorViewEngine类中。
         //ViewLocationFormats:"~/Views/{1}/{0}.cshtml","~/Views/{1}/{0}.vbhtml", "~/Views/Shared/{0}.cshtml","~/Views/Shared/{0}.vbhtml"
         //AreaViewLocationFormats:"~/Areas/{2}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Views/{1}/{0}.vbhtml", "~/Areas/{2}/Views/Shared/{0}.cshtml","~/Areas/{2}/Views/Shared/{0}.vbhtml"
         string  viewPath = GetPath(controllerContext, ViewLocationFormats, AreaViewLocationFormats,  "ViewLocationFormats" , viewName, controllerName, CacheKeyPrefixView, useCache,  out  viewLocationsSearched);
         
         
         string  masterPath = GetPath(controllerContext, MasterLocationFormats, AreaMasterLocationFormats,  "MasterLocationFormats" , masterName, controllerName, CacheKeyPrefixMaster, useCache,  out  masterLocationsSearched);
 
         if  (String.IsNullOrEmpty(viewPath) || (String.IsNullOrEmpty(masterPath) && !String.IsNullOrEmpty(masterName)))
         {
             return  new  ViewEngineResult(viewLocationsSearched.Union(masterLocationsSearched));
         }
 
         return  new  ViewEngineResult(CreateView(controllerContext, viewPath, masterPath),  this );
     }
}

啪啪啪

  GetPath方法在寻找【视图页】时,首先将当前请求的Controller和Action的名称添加到地址格式化器中,这样就有了要寻找的地址(们),之后就来检查格式化后的地址是否真的存在指定的【视图页】。如果是通过手机端来请求,则会对格式化之后的地址进行再进行处理(如:Index.cshtml修改为Index.Mobile.cshtml),之后再检查新地址下是否存在【视图页】。

注:默认情况下会先检查是否为手机端访问!

口说无凭,上源码吧:

  VirtualPathProviderViewEngine
  DisplayModeProvider
  DefaultDisplayMode

由以上源码可知,默认情况下,ASP.NET MVC4在DisplayModeProvider中定义了一个含有两个DefaultDisplayMode对象(用于对地址再处理)的集合:

1
2
3
4
5
6
7
8
9
public  static  readonly  string  MobileDisplayModeId =  "Mobile" ;
private  readonly  List<IDisplayMode> _displayModes =  new  List<IDisplayMode>
{
     new  DefaultDisplayMode(MobileDisplayModeId)
     {
         ContextCondition = context => context.GetOverriddenBrowser().IsMobileDevice
     },
     new  DefaultDisplayMode()
};

由于处理时,是按照遍历执行_displayModes集合中DefaultDisplayMode对象的GetDisplayInfo方法(索引值从0开始),所以无论是 PC 还是 Phone发送的请求,都会先执集合中的第一个DefaultDisplayMode对象(判断是否为手机的请求)。如果Phone端发送请求,会去寻找xxx.Mobile.cshtml,如果没有的话,就继续执行第二个DefaultDisplayMode对象,去寻找xxx.cshtml。如果是PC端发送请求,也是首先执行第一个DefaultDisplayMode对象,但是由于不满足 context => context.GetOverriddenBrowser().IsMobileDevice 条件,所以还是需要去执行第二个DefaultDisplayMode对象,去寻找xxx.cshtml。

 扩展:
1、指定DisplayMode

模拟需求:对Phone端用户的某个Action请求,返回电脑版网页。

1
2
3
4
5
6
7
public  ActionResult Index()
{
     //一些判断条件
     this .ControllerContext.DisplayMode = DisplayModeProvider.Instance.Modes[1];
     DisplayModeProvider.Instance.RequireConsistentDisplayMode =  true ;
     return  View();
}

  根据上述设置,即使是Phone端的请求并且还存在Index.Mobile.cshtml文件,也会去执行Index.cshtml,即:实现Phone用户访问电脑版网页。

2、自定义DisplayMode

模拟需求:为Android 2.3用户设置特定的页面

先创建一个类似于Index.Android23.cshtml 的页面,然后在Global.asax中做如下设置即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public  class  MvcApplication : System.Web.HttpApplication
{
     protected  void  Application_Start()
     {
         AreaRegistration.RegisterAllAreas();
 
         WebApiConfig.Register(GlobalConfiguration.Configuration);
         FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
         RouteConfig.RegisterRoutes(RouteTable.Routes);
         BundleConfig.RegisterBundles(BundleTable.Bundles);
         AuthConfig.RegisterAuth();
 
         DisplayModeProvider.Instance.Modes.Insert(0,  new  DefaultDisplayMode( "Android23" )
         {
             ContextCondition = (context => context.GetOverriddenUserAgent().IndexOf
             ( "Android 2.3" , StringComparison.OrdinalIgnoreCase) >= 0)
         });
     }
}

 

以上就是所有内容,如有不适之处,请指正!!!

 


本文转自武沛齐博客园博客,原文链接:http://www.cnblogs.com/wupeiqi/p/3597845.html,如需转载请自行联系原作者

目录
相关文章
|
3月前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
42 0
|
13天前
|
前端开发 Java Spring
数据之桥:深入Spring MVC中传递数据给视图的实用指南
数据之桥:深入Spring MVC中传递数据给视图的实用指南
29 3
|
1月前
|
开发框架 前端开发 .NET
进入ASP .net mvc的世界
进入ASP .net mvc的世界
29 0
|
1月前
mvc.net分页查询案例——mvc-paper.css
mvc.net分页查询案例——mvc-paper.css
5 0
|
1月前
|
存储 设计模式 前端开发
请解释 Web 应用程序的 MVC(模型-视图-控制器)架构。
【2月更文挑战第26天】【2月更文挑战第89篇】请解释 Web 应用程序的 MVC(模型-视图-控制器)架构。
|
1月前
|
开发框架 前端开发 .NET
C# .NET面试系列六:ASP.NET MVC
<h2>ASP.NET MVC #### 1. MVC 中的 TempData\ViewBag\ViewData 区别? 在ASP.NET MVC中,TempData、ViewBag 和 ViewData 都是用于在控制器和视图之间传递数据的机制,但它们有一些区别。 <b>TempData:</b> 1、生命周期 ```c# TempData 的生命周期是短暂的,数据只在当前请求和下一次请求之间有效。一旦数据被读取,它就会被标记为已读,下一次请求时就会被清除。 ``` 2、用途 ```c# 主要用于在两个动作之间传递数据,例如在一个动作中设置 TempData,然后在重定向到另
99 5
|
3月前
|
XML 前端开发 定位技术
C#(NET Core3.1 MVC)生成站点地图(sitemap.xml)
C#(NET Core3.1 MVC)生成站点地图(sitemap.xml)
25 0
|
3月前
|
前端开发
.net core mvc获取IP地址和IP所在地(其实是百度的)
.net core mvc获取IP地址和IP所在地(其实是百度的)
124 0
|
5月前
|
开发框架 自然语言处理 前端开发
基于ASP.NET MVC开发的、开源的个人博客系统
基于ASP.NET MVC开发的、开源的个人博客系统
52 0
|
8月前
|
存储 开发框架 前端开发
[回馈]ASP.NET Core MVC开发实战之商城系统(五)
经过一段时间的准备,新的一期【ASP.NET Core MVC开发实战之商城系统】已经开始,在之前的文章中,讲解了商城系统的整体功能设计,页面布局设计,环境搭建,系统配置,及首页【商品类型,banner条,友情链接,降价促销,新品爆款】,商品列表页面,商品详情等功能的开发,今天继续讲解购物车功能开发,仅供学习分享使用,如有不足之处,还请指正。
116 0