在上一篇文章中,我们知道了通过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. 基于Socket网络编程

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/a2011480169/article/details/73602708 博客核心内容: 1.Sock ...

  2. (转) Java RandomAccessFile与MappedByteBuffer

    RandomAccessFile RandomAccessFile是用来访问那些保存数据记录的文件的,你就可以用seek( )方法来访问记录,并进行读写了.这些记录的大小不必相同:但是其大小和位置必须 ...

  3. C++开源项目等收集

    VLC 是一款自由.开源的跨平台多媒体播放器及框架,可播放大多数多媒体文件,以及 DVD.音频 CD.VCD 及各类流媒体协议. Downloading vlc-2.2.4.tar.xz Thanks ...

  4. V8 下的垃圾回收机制

    V8 实现了准确式 GC,GC 算法采用了分代式垃圾回收机制.因此,V8 将内存(堆)分为新生代和老生代两部分. 1.新生代算法 新生代中的对象一般存活时间较短,使用 Scavenge GC 算法. ...

  5. ASP.NET MVC 一款可预览、裁剪头像上传组件

    今天介绍一款Web上常用的头像上传组件,常用于头像上传时对用户上传的图片进行裁剪并实时预览,最终效果如下: 源代码结构: Github地址: https://github.com/FrankFan/A ...

  6. centos7 mysql数据库安装和配置(转, 未验证)

    一.系统环境 yum update升级以后的系统版本为 [root@yl-web yl]# cat /etc/redhat-release CentOS Linux release 7.1.1503 ...

  7. oracle登陆提示“ora-01031 insufficient privileges”

    本机装了服务端的oracle11.2g,一直没用,中间换过系统的登陆用户.今早发现登陆数据库时发现老提示“ora-01031 insufficient privileges”,以为监听没配置好,试过了 ...

  8. 关于dealloc 注意事项

    以下讨论在 MRC 下. 1,不要在init和dealloc函数中使用accessor Don’t Use Accessor Methods in Initializer Methods and de ...

  9. Java Lombok

    Reducing Boilerplate Code with Project Lombok https://projectlombok.org/features/all https://github. ...

  10. linux每日命令(9):cp命令

    一.命令格式: cp [参数] source dest 或 cp [参数] source... directory 二.命令功能: 将源文件复制至目标文件,或将多个源文件复制至目标目录. 三. 命令参 ...