在上一篇文章中,我们知道了通过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的具体信息

  1. 获取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();

}

返回结果为:

  1. 获取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]视图是如何呈现的 (续)的更多相关文章

  1. [ASP.NET MVC]视图是如何呈现的

    为了搞清楚ASP.NET MVC的请求过程,我们计划从结果追踪到源头.使用VS2012创建一个空白的ASP.NET MVC项目 然后创建一个HelloController 创建一个HelloView. ...

  2. ASP.NET MVC 视图(五)

    ASP.NET MVC 视图(五) 前言 上篇讲解了视图中的分段概念.和分部视图的使用,本篇将会对Razor的基础语法简洁的说明一下,前面的很多篇幅中都有涉及到视图的调用,其中用了很多视图辅助器,也就 ...

  3. ASP.NET MVC 视图(四)

    ASP.NET MVC 视图(四) 前言 上篇对于利用IoC框架对视图的实现进行依赖注入,最后还简单的介绍一下自定义的视图辅助器是怎么定义和使用的,对于Razor语法的细节和辅助器的使用下篇会说讲到, ...

  4. ASP.NET MVC 视图(一)

    ASP.NET MVC 视图(一) 前言 从本篇开始就进入到了MVC中的视图部分,在前面的一些篇幅中或多或少的对视图和视图中的一些对象的运用进行了描述,不过毕竟不是视图篇幅说的不全面,本篇首先为大家讲 ...

  5. Asp.net MVC 视图引擎

    Asp.net MVC视图引擎有两种: 1.ASPX View Engine 这个做过WebForm的人都清楚 设计目标:一个用于呈现Web Form页面的输出的视图引擎. 2.Razor View ...

  6. ASP.NET MVC 之Model的呈现

    ASP.NET MVC 之Model的呈现(仅此一文系列三) 本文目的 我们来看一个小例子,在一个ASP.NET MVC项目中创建一个控制器Home,只有一个Index: public class H ...

  7. 【ASP.NET MVC系列】浅谈ASP.NET MVC 视图

    ASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作 ...

  8. ASP.NET MVC 视图(三)

    ASP.NET MVC 视图(三) 前言 上篇对于Razor视图引擎和视图的类型做了大概的讲解,想必大家对视图的本身也有所了解,本篇将利用IoC框架对视图的实现进行依赖注入,在此过程过会让大家更了解的 ...

  9. ASP.NET MVC 视图(二)

    ASP.NET MVC 视图(二) 前言 上篇中对于视图引擎只是做了简单的演示,对于真正的理解视图引擎的工作过程可能还有点模糊,本篇将会对由MVC框架提供给我们的Razor视图引擎的整个执行过程做一个 ...

随机推荐

  1. python+requests接口自动化完整项目设计源码

    前言 有很多小伙伴吵着要完整的项目源码,完整的项目属于公司内部的代码,这个是没法分享的,违反职业道德了,就算别人分享了,也只适用于本公司内部的业务. 所以用例的代码还是得自己去一个个写,我只能分享项目 ...

  2. 病毒木马查杀实战第020篇:Ring3层主动防御之基本原理

    前言 假设说我们的计算机中安装有杀毒软件,那么当我们有意或无意地下载了一个恶意程序后.杀软一般都会弹出一个对话框提示我们,下载的程序非常可能是恶意程序,建议删除之类的.或者杀软就不提示.直接删除了:或 ...

  3. 后台任务hangfire

    Installation¶ There are a couple of packages for Hangfire available on NuGet. To install Hangfire in ...

  4. SoapUI Pro Project Solution Collection-XML assert

    in soapui the XML object used here is from  org.w3c.dom package so you need to read this article car ...

  5. struts2:表单标签

    目录 表单标签1. form标签2. submit标签3. checkbox标签4. checkboxlist标签5. combobox标签6. doubleselect标签7. head标签8. f ...

  6. Latex学习(一)

    要在整个系统中使用TEX Live的字体(假定你有足够的权限),请依照下面的步骤来做: 1.将texlive-fontconfig.conf文件复制到/etc/fonts/conf.d/09-texl ...

  7. 第三部分:Android 应用程序接口指南---第四节:动画和图形---第一章 属性动画及动画与图形概述

    第1章 属性动画及动画与图形概述 Android提供了一系列强大的API来把动画加到UI元素中,以及绘制自定义的2D和3D图像中去.下面的几节将综述这些可用的API以及系统的功能,同时帮你做出最优的选 ...

  8. 使用vw做移动端页面的适配

    Flexible到今天也有几年的历史了,解救了很多同学针对于H5页面布局的适配问题.而这套方案也相对而言是一个较为成熟的方案.简单的回忆一下,当初为了能让页面更好的适配各种不同的终端,通过Hack手段 ...

  9. Socket网络编程--聊天程序(2)

    上一节简单如何通过Socket创建一个连接,然后进行通信.只是每个人只能说一句话.而且还是必须说完才会接收到信息,总之是很不方便的事情.所以这一小节我们将对上一次的程序进行修改,修改成每个人可以多说话 ...

  10. Blink

    https://help.aliyun.com/document_detail/66088.html?spm=a2c4g.11186623.6.602.58ff5686FP4Ihh