[ASP.NET MVC]视图是如何呈现的 (续)
在上一篇文章中,我们知道了通过Controller执行ActionResult的Execute可以找到对应Controler对应的ViewEngine,然后在View中把Action的结果显示出来。那么ViewEngine到底是如何工作的?
我们首先从ViewReult的FindView方法开始
|
protectedoverrideViewEngineResult FindView(ControllerContext context) { ViewEngineResult result = ViewEngineCollection.FindView(context, ViewName, MasterName); if (result.View != null) { return result; } // we need to generate an exception containing all the locations we searched … } |
根据ControllerContext和ViewName,以及MasterName找到对应的ViewEngineResult对象。我们还是以HelloController和Index为例。那么这里result将返回Views/Hello/Index.cshtml编译后的实例。我们进入FindView方法,看看其具体的实现。
上述方法调用的是ViewEngineCollection类的虚方法FindView
|
publicvirtualViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName) { if (controllerContext == null) { thrownewArgumentNullException("controllerContext"); } if (String.IsNullOrEmpty(viewName)) { thrownewArgumentException(MvcResources.Common_NullOrEmpty, "viewName"); } return Find(e => e.FindView(controllerContext, viewName, masterName, true), e => e.FindView(controllerContext, viewName, masterName, false)); } |
它又调用其私有的方法
|
privateViewEngineResult Find(Func<IViewEngine, ViewEngineResult> cacheLocator, Func<IViewEngine, ViewEngineResult> locator) { // First, look up using the cacheLocator and do not track the searched paths in non-matching view engines // Then, look up using the normal locator and track the searched paths so that an error view engine can be returned return Find(cacheLocator, trackSearchedPaths: false) ?? Find(locator, trackSearchedPaths: true); } |
然后又调用
|
privateViewEngineResult Find(Func<IViewEngine, ViewEngineResult> lookup, bool trackSearchedPaths) { // Returns // 1st result // OR list of searched paths (if trackSearchedPaths == true) // OR null ViewEngineResult result; List<string> searched = null; if (trackSearchedPaths) { searched = newList<string>(); } foreach (IViewEngine engine in CombinedItems) { if (engine != null) { result = lookup(engine); if (result.View != null) { return result; } if (trackSearchedPaths) { searched.AddRange(result.SearchedLocations); } } } if (trackSearchedPaths) { // Remove duplicate search paths since multiple view engines could have potentially looked at the same path returnnewViewEngineResult(searched.Distinct().ToList()); } else { returnnull; } } |
注意,这里传入了一个Func<IViewEngine, ViewEngineResult>。输入一个IViewEngine类型,请注意ViewEngine是实际来自ViewEnglieCollection的属性CombinedItems。该对象来自IResolver<IEnumerable<IViewEngine>>接口的Current属性,其类型为IEnuerable<IViewEngine>。其实就是传入一个IViewEngine,然后一个ViewEngileResult。比如下面的例子:
|
// details of ViewEngineCollection.Find(*) Func<IViewEngine, System.Web.Mvc.ViewEngineResult> cacheLocator = e => e.FindView(ControllerContext, "ViewInstance", "", false); IViewEngine razorViewEngine = newRazorViewEngine(); System.Web.Mvc.ViewEngineResult result = cacheLocator(razorViewEngine); |
请注意,IResolver<IEnumerable<IViewEngine>>的默认实例是newMultiServiceResolver<IViewEngine>(() => Items);
【有待于确认】。我们查看其构造函数,可以发现
|
public MultiServiceResolver(Func<IEnumerable<TService>> itemsThunk) { if (itemsThunk == null) { thrownewArgumentNullException("itemsThunk"); } _itemsThunk = itemsThunk; _resolverThunk = () => DependencyResolver.Current; _itemsFromService = newLazy<IEnumerable<TService>>(() => _resolverThunk().GetServices<TService>()); } |
也就是说IResolver的实例来自DependencyResolver.Current。通过DependencyResolver的定义,我们得知Current属性返回的单列new DenpendencyResolver.InnerCurrent,InnerCurrent其实就是newDefaultDependencyResolver()。DedendencyResolver在创建,创建单列的DefaultDependencyResolver,并将其赋值给_current和_currentCache。_currentCache对应的是InnerCurrentCache,该属性在创建View使没有使用,在创建Controller的时候会使用。
然后,调用ViewResult对象View属性的Render方法,次方法首先会创建View实例。
|
object instance = null; Type type = BuildManager.GetCompiledType(ViewPath); if (type != null) { instance = ViewPageActivator.Create(_controllerContext, type); } |
而实际上,现在的ViewPageActivator实际是newBuildManagerViewEngine.DefaultViewPageActivator(dependencyResolver),而这里的denpendencyResolver就是DefaultDependencyResolver。
OK,我们最后来看一下instance是如何创建的:
|
_resolverThunk().GetService(type) ?? Activator.CreateInstance(type); |
请注意,_resolverThunk = () => DependencyResolver.Current;由此可见在默认的PageActivator内部的私有Fun变量_resolverThunk同样来自DefaultDependencyResolver.Current。
而instance要么DefaultDependencyResolver的GetService()创建,要么通过Activator.CreateInstance来创建,其实它们内部根本没有多少差别。
|
publicobject GetService(Type serviceType) { // Since attempting to create an instance of an interface or an abstract type results in an exception, immediately return null // to improve performance and the debugging experience with first-chance exceptions enabled. if (serviceType.IsInterface || serviceType.IsAbstract) { returnnull; } try { returnActivator.CreateInstance(serviceType); } catch { returnnull; } } |
由此可见,GetService内部还是调用了Activator.CreateInstance方法创建实例。
剖析如何获取View的具体信息
- 获取View的Path
|
// show the details of retrieving view path publicActionResult List() { string[] ViewLocationFormats = new[] { "~/Views/{1}/{0}.cshtml", "~/Views/{1}/{0}.vbhtml", "~/Views/Shared/{0}.cshtml", "~/Views/Shared/{0}.vbhtml" }; string name = "List"; string controllerName = "InnerView"; string areaName = ""; List<ViewLocation> allLocations = newList<ViewLocation>(); foreach (string viewLocationFormat in ViewLocationFormats) allLocations.Add(newViewLocation(viewLocationFormat)); DisplayModeProvider instance = DisplayModeProvider.Instance; for (int i = 0; i < allLocations.Count; i++) { ViewLocation location = allLocations[i]; string virtualPath = location.Format(name, controllerName, areaName); DisplayInfo virtualPathDisplayInfo = instance.GetDisplayInfoForVirtualPath(virtualPath, ControllerContext.HttpContext, path => FileExists(ControllerContext, path), null); if (virtualPathDisplayInfo == null) continue; var viewPath = virtualPathDisplayInfo.FilePath; Response.Write(viewPath); } return View(); } |
返回结果为:

- 获取View的对象
|
publicActionResult Activator() { // remove the dependency IDependencyResolver dependencyResolver = DependencyResolver.Current; IResolver<IViewPageActivator> activatorResolver = newSingleServiceResolver<IViewPageActivator>( () => null, newDefaultViewPageActivator(dependencyResolver), "BuildManagerViewEngine constructor"); IViewPageActivator pageActivator = activatorResolver.Current; // HelloMVC.Controllers.InnerViewController Object controllerInstance = pageActivator.Create(ControllerContext, this.GetType()); // Page instance IBuildManager buildManager = newBuildManagerWrapper(); Object viewpageInstance = pageActivator.Create(ControllerContext, buildManager.GetCompiledType("~/Views/InnerView/List.cshtml ")); Response.Write(string.Format("controllerInstance is {0} <br /> viewpageInstance is {1}", controllerInstance.GetType(), viewpageInstance.GetType())); return View(); } |

http://www.professionals-helpdesk.com/2012/08/exploring-mvc-framwwork-in-deep_10.html exploring MVC framework in deep – DependencyResolver Class
[ASP.NET MVC]视图是如何呈现的 (续)的更多相关文章
- [ASP.NET MVC]视图是如何呈现的
为了搞清楚ASP.NET MVC的请求过程,我们计划从结果追踪到源头.使用VS2012创建一个空白的ASP.NET MVC项目 然后创建一个HelloController 创建一个HelloView. ...
- ASP.NET MVC 视图(五)
ASP.NET MVC 视图(五) 前言 上篇讲解了视图中的分段概念.和分部视图的使用,本篇将会对Razor的基础语法简洁的说明一下,前面的很多篇幅中都有涉及到视图的调用,其中用了很多视图辅助器,也就 ...
- ASP.NET MVC 视图(四)
ASP.NET MVC 视图(四) 前言 上篇对于利用IoC框架对视图的实现进行依赖注入,最后还简单的介绍一下自定义的视图辅助器是怎么定义和使用的,对于Razor语法的细节和辅助器的使用下篇会说讲到, ...
- ASP.NET MVC 视图(一)
ASP.NET MVC 视图(一) 前言 从本篇开始就进入到了MVC中的视图部分,在前面的一些篇幅中或多或少的对视图和视图中的一些对象的运用进行了描述,不过毕竟不是视图篇幅说的不全面,本篇首先为大家讲 ...
- Asp.net MVC 视图引擎
Asp.net MVC视图引擎有两种: 1.ASPX View Engine 这个做过WebForm的人都清楚 设计目标:一个用于呈现Web Form页面的输出的视图引擎. 2.Razor View ...
- ASP.NET MVC 之Model的呈现
ASP.NET MVC 之Model的呈现(仅此一文系列三) 本文目的 我们来看一个小例子,在一个ASP.NET MVC项目中创建一个控制器Home,只有一个Index: public class H ...
- 【ASP.NET MVC系列】浅谈ASP.NET MVC 视图
ASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作 ...
- ASP.NET MVC 视图(三)
ASP.NET MVC 视图(三) 前言 上篇对于Razor视图引擎和视图的类型做了大概的讲解,想必大家对视图的本身也有所了解,本篇将利用IoC框架对视图的实现进行依赖注入,在此过程过会让大家更了解的 ...
- ASP.NET MVC 视图(二)
ASP.NET MVC 视图(二) 前言 上篇中对于视图引擎只是做了简单的演示,对于真正的理解视图引擎的工作过程可能还有点模糊,本篇将会对由MVC框架提供给我们的Razor视图引擎的整个执行过程做一个 ...
随机推荐
- SVN clean失败解决方法【转】
原文地址:http://blog.csdn.net/victory08/article/details/42100325/ svn执行clean up后出现提示:svn cleanup failed– ...
- 自动化运维之-PXE实现系统批量自动安装
转自:https://www.linuxidc.com/Linux/2017-10/147379.htm 本节索引 需求分析 PXE简介 整体方案 服务选择 功能实现 安装调试 错误分析 总结 1 需 ...
- Unity Shader-后处理:Bloom全屏泛光
一.简介 今天来学习一下全屏Bloom效果,有时候也叫Glow效果,中文一般叫做“全屏泛光”,这是一种可以模拟出HDR的全屏后处理效果,但是实现原理与HDR相差很远,效果比HDR差一些,但是比HD ...
- String to Integer (atoi) leetcode java
题目: Implement atoi to convert a string to an integer. Hint: Carefully consider all possible input ca ...
- storm杂谈之Why use netty as transport instead of zeromq
Storm后来用Netty来代替了zmq,这个能够參考一下两篇blog 这两篇blog具体的阐述原因以及一些性能測试, 大家參考一下 Reference 1.Netty 4 Reduces GC Ov ...
- Android 组件系列-----Activity生命周期
本篇随笔将会深入学习Activity,包括如何定义多个Activity,并设置为默认的Activity.如何从一个Activity跳转到另一个Activity,还有就是详细分析Activity的生命周 ...
- Kubernetes1.2如何使用iptables
转:http://blog.csdn.net/horsefoot/article/details/51249161 本次分析的kubernetes版本号:v1.2.1-beta.0. Kubernet ...
- How can R and Hadoop be used together?
Referer: http://www.quora.com/How-can-R-and-Hadoop-be-used-together/answer/Jay-Kreps?srid=OVd9&s ...
- Atitit 数据库 标准库 sdk 函数库 编程语言 mysql oracle attilax总结
Atitit 数据库 标准库 sdk 函数库 编程语言 mysql oracle attilax总结 1.1. 常见的编程语言以及数据库 sql内部函数库标准化库一般有以下api1 1.2. 各个 ...
- 菜鸟教程之工具使用(七)——从GIt上导出Maven项目
今天继续我们的工具教程,公司用Git作为版本控制工具,所以最近一直在跟Git打交道.也是一边学习一边使用,于是想做一些入门教程,一来自己总结一下,二来还能帮助一些刚刚接触Git的朋友.一举两得,何乐而 ...