有些人要问题,为什么我要学框架?这里我简单说一下,深入理解一个框架,给你带来最直接的好处:

  1. 使用框架时,遇到问题可以快速定位,并知道如何解决;
  2. 当框架中有些功能用着不爽时,你可以自由扩展,实现你想要的操作,甚至可以拿到源码直接修改;
  3. 想成为框架师的必经之路;
  4. 提取框架中的优秀代码和思想,为己所用;

更多好处,你可以自己去体会,有兴趣的可以看一下asp.net中 mvc部分的源码:http://aspnetwebstack.codeplex.com/

本文目的

上一篇文章是让你明白MVC最核心的两个流程(如果没看过请猛戳这里,只需耽误你打盹的几分钟)。我们接着上篇从ControllerActionInvoker的InvokeAction方法执行Action说起:

//执行Action,并得到ActionResult
ActionResult actionResult = method.Invoke(controllerContext.Controller,
parameters.ToArray()) as ActionResult; //最终ActionResult用HttpResponse将数据传回客户进行显示
actionResult.ExecuteResult(controllerContext);

本文的目的就是让你明白这段代码到底做了哪些事情?MVC中的Controller如何找到View,并进行显示。

开始旅程

先放上与本文相关的类结构图:

此图看起来结构相当复杂,但其实他很简单,给我两分钟,我会让你明白这些鬼东西到底是什么、有什么关系?

先说ActionResult,从图上看,ActionResult是个抽象类,他的子类有很多,比如JsonResult,ContentResult,ViewResult,EmptyResult等等。这个东西大家用MVC的时候常常接触,比如:

public class HomeController:Controller
{
public ActionResult Index()
{
return View();
} public ActionResult GetInfo()
{
...
return Json(obj);
} public ActionResult GetContent()
{
return Content("test");
}
}

上面三个Action返回分别对应ViewResult、JsonResult、ContentResult,而我图中只画ViewResult,因为它是我们最常用的一个ActionResult,而且是最复杂的一个(因为要负责View的显示)。而看看ContentResult的核心源码,我想简单的大家都笑翻了:

public class ContentResult : ActionResult
{
public string Content { get; set; } public override void ExecuteResult(ControllerContext context)
{
HttpResponseBase response = context.HttpContext.Response; if (Content != null)
{
response.Write(Content);
}
}
}

它的实现和上面我画的结构图完全没有半毛钱关系,直接一个Response.Write输出就完成了。所以我用ViewResult来写本文。

接下来注意ViewEngines这个静态类,看一下它的源码:

 public static class ViewEngines
{
private static readonly ViewEngineCollection _engines = new ViewEngineCollection
{
new WebFormViewEngine(),
new RazorViewEngine(),
}; public static ViewEngineCollection Engines
{
get { return _engines; }
}
}

只有一个静态只读的ViewEngineCollection类型的成员,初始化时封装了两个视图引擎,WebFormViewEngine和RazorViewEngine?这两个是什么?为了方便大家理解,我们看看RazorViewEngine的源码(WebFormViewEngine基本一样,篇幅限制下面我只用Razor举例):

public class RazorViewEngine : BuildManagerViewEngine
{
internal static readonly string ViewStartFileName = "_ViewStart"; //存储ViewStart模板的 public RazorViewEngine(IViewPageActivator viewPageActivator)
: base(viewPageActivator)
{
//这些构造大家应该觉得很亲切
ViewLocationFormats = new[]
{
"~/Views/{1}/{0}.cshtml",
"~/Views/{1}/{0}.vbhtml",
"~/Views/Shared/{0}.cshtml",
"~/Views/Shared/{0}.vbhtml"
};
MasterLocationFormats = new[]
{
"~/Views/{1}/{0}.cshtml",
"~/Views/{1}/{0}.vbhtml",
"~/Views/Shared/{0}.cshtml",
"~/Views/Shared/{0}.vbhtml"
};
PartialViewLocationFormats = new[]
{
"~/Views/{1}/{0}.cshtml",
"~/Views/{1}/{0}.vbhtml",
"~/Views/Shared/{0}.cshtml",
"~/Views/Shared/{0}.vbhtml"
}; FileExtensions = new[]
{
"cshtml",
"vbhtml",
};
} protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
var view = new RazorView(controllerContext, viewPath,
layoutPath: masterPath, runViewStartPages: true, viewStartFileExtensions: FileExtensions, viewPageActivator: ViewPageActivator)
{
DisplayModeProvider = DisplayModeProvider
};
return view;
}
}

从代码中可以看出,RazorViewEngine只是封装了View文件的相关路径。后面我会说明他们是怎么被用到的。

知道上面几个类的基本情况后,看一下它们的执行流程,你会对各个类的功能有个大致的了解,当控制器的Action返回一个ViewResult时并执行ExecuteResult时(文章开始部分介绍的代码):

  1. 从ViewEngines的Engines中获取ViewResultEngine对象,实质是遍历RazorViewEngine和WebFormViewEngine,然后通过它们本身继承VirtualPathProviderViewEngine的成员函数FindView创建ViewResultEngine【从下面的时序图中可以看出,虽然MVC把这个东西藏的很深,但基本都是在父类与子类间传递,结构还算清晰】;
  2. 通过得到的ViewResultEngine中的View执行Render进行界面显示,内部会调用RazorView的RenderView进行最终的显示处理;

核心流程就是上面两步,执行时序图如下所示(点击查看大图):

现在注意流程的第17步,即执行BuildManagerCompliedView的Render函数,这个函数是View显示的灵魂:

        public virtual void Render(ViewContext viewContext, TextWriter writer)
{
object instance = null; //这个ViewPath就是根据RazorViewEngine的模板位置得到的View具体路径,在RazorViewEngine创建ViewEngineResult传进来的
Type type = BuildManager.GetCompiledType(ViewPath);
if (type != null)
{
instance = ViewPageActivator.Create(_controllerContext, type);
} if (instance == null)
{
throw new InvalidOperationException(
String.Format(
CultureInfo.CurrentCulture,
MvcResources.CshtmlView_ViewCouldNotBeCreated,
ViewPath));
} RenderView(viewContext, writer, instance);
}

上面根据ViewPath生成的那个instance是什么?看看RazorView中RendView的实现就知道了:

 protected override void RenderView(ViewContext viewContext, TextWriter writer, object instance)
{
WebViewPage webViewPage = instance as WebViewPage;
//其它代码先不管
webViewPage.ExecutePageHierarchy(new WebPageContext(context: viewContext.HttpContext, page: null, model: null), writer, startPage);
}

原来是个WebViewPage的对象,查一查MSDN就知道,所有View都是从WebViewPage的泛型WebViewPage<TMode>直接继承出来的。我们来看一下这个类:

    public abstract class WebViewPage : WebPageBase, IViewDataContainer, IViewStartPageChild
{
private ViewDataDictionary _viewData;
private DynamicViewDataDictionary _dynamicViewData; public AjaxHelper<object> Ajax { get; set; }
public HtmlHelper<object> Html { get; set; } public object Model
{
get { return ViewData.Model; }
} public TempDataDictionary TempData
{
get { return ViewContext.TempData; }
} public UrlHelper Url { get; set; } public dynamic ViewBag
{
get
{
if (_dynamicViewData == null)
{
_dynamicViewData = new DynamicViewDataDictionary(() => ViewData);
}
return _dynamicViewData;
}
} public ViewContext ViewContext { get; set; } public override void ExecutePageHierarchy()
{
Execute(); //这个函数是基类中定义的抽象函数,会在最终aspx/cshtml生成的类中被重载
} public virtual void InitHelpers()
{
Ajax = new AjaxHelper<object>(ViewContext, this);
Html = new HtmlHelper<object>(ViewContext, this);
Url = new UrlHelper(ViewContext.RequestContext);
}
}

是不是在里面看到了很多平时最常用的属性。当用ExecutePageHierarchy生成页面时,实际会调用Execute函数,这个函数会在最终cshtml,aspx等生成的类中被重载。我们看一个简单的例子:

假设我们有一个强类型的视图:/Views/Home/Index.cshtml,一个简单的DemoModel类型,只有一个UserName属性:

@model Controllers.DemoModel
<div>Index</div>
@Model.UserName

那么这个Index.cshtml被编译后就会生成下面这个类:

public class _Page_Views_Home_Index_cshtml : WebViewPage<DemoModel>
{
public override void Execute()
{
this.WriteLiteral("<div>Index</div");
this.Write(Model.UserName);
}
}

就这样,最终将WEB显示出来。

仅此一文让你明白ASP.NET MVC 之View的显示的更多相关文章

  1. 仅此一文让你明白ASP.NET MVC 之View的显示(仅此一文系列二)

    题外话 一周之前写的<仅此一文让你明白ASP.NET MVC原理>受到了广大学习ASP.NET MVC同学的欢迎,于是下定决心准备把它写成一个系列,以满足更多求知若渴的同学们.蒋金楠老师已 ...

  2. 仅此一文让你明白ASP.NET MVC 之Model的呈现(仅此一文系列三)

    本文目的 我们来看一个小例子,在一个ASP.NET MVC项目中创建一个控制器Home,只有一个Index: public class HomeController : Controller { pu ...

  3. 仅此一文让你明白ASP.NET MVC 之Model的呈现

    本文目的 我们来看一个小例子,在一个ASP.NET MVC项目中创建一个控制器Home,只有一个Index: public class HomeController : Controller { pu ...

  4. 仅此一文让你明白ASP.NET MVC原理

    ASP.NET MVC由以下两个核心组成部分构成: 一个名为UrlRoutingModule的自定义HttpModule,用来解析Controller与Action名称: 一个名为MvcHandler ...

  5. 【转】仅此一文让你明白ASP.NET MVC原理

    原文地址:http://www.cnblogs.com/DotCpp/p/3269043.html ASP.NET MVC由以下两个核心组成部分构成: 一个名为UrlRoutingModule的自定义 ...

  6. ASP.NET MVC 之View

    仅此一文让你明白ASP.NET MVC 之View的显示(仅此一文系列二)   题外话 一周之前写的<仅此一文让你明白ASP.NET MVC原理>受到了广大学习ASP.NET MVC同学的 ...

  7. TransactionScope事务处理方法介绍及.NET Core中的注意事项 SQL Server数据库漏洞评估了解一下 预热ASP.NET MVC 的VIEW [AUTOMAPPER]反射自动注册AUTOMAPPER PROFILE

    TransactionScope事务处理方法介绍及.NET Core中的注意事项   作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/10170712.ht ...

  8. 返璞归真 asp.net mvc (4) - View/ViewEngine

    原文:返璞归真 asp.net mvc (4) - View/ViewEngine [索引页] [源码下载] 返璞归真 asp.net mvc (4) - View/ViewEngine 作者:web ...

  9. ASP.NET MVC 中 View 的设计

    1. 前言  感觉有好长时间没有接触View 了,周末闲来无事,翻翻书桌上的书来回顾回顾ASP.NET MVC中View的相关内容. 2. View概述  View 通过应用程序在Action 中返回 ...

随机推荐

  1. 初学Direct X(8) ——碰撞检测

    初学Direct X(8) --碰撞检测 真正让一个游戏鹤立鸡群的是程序对碰撞的响应有多好,这里介绍两种检测的方法: 1) 基于边框的碰撞检测 2) 基于距离的碰撞检测 1. 基于边框的碰撞检测 1. ...

  2. Java应用基础微专业-设计篇

    第1章--抽象与接口 1.1 抽象 An abstract class can be created without abstract methods, the purpose of doing th ...

  3. C#使用EF连接PGSql数据库

    前言 由于项目需要,使用到了PGSql数据库,说实话这是第一次接触并且听说PGSql(PostgreSQL)关系型数据库,之前一直使用的都是SqlServer,一头雾水的各种找资源,终于将PGSql与 ...

  4. 【WXS数据类型】RegExp

    生成 regexp 对象需要使用 getRegExp函数,注意与JS的使用方法不同( new RegExp(pattern,modifiers);) 原型:getRegExp(pattern, mod ...

  5. 数据库Mysql的学习(四)-表的记录操作

    ,);//指定插入的顺序 ,);//按照默认的插入 ,),(,)(,);//同时插入多条数据 //将查询结果插入表中 CREATE TABLE TEXT( category_id INT PRIMAR ...

  6. 【机器学习】多项式回归python实现

    [机器学习]多项式回归原理介绍 [机器学习]多项式回归python实现 [机器学习]多项式回归sklearn实现 使用python实现多项式回归,没有使用sklearn等机器学习框架,目的是帮助理解算 ...

  7. HADOOP/HDFS Essay

    HDFS架构 the core of HADOOP/distributed systems is storeage(HDFS) and resource manager(YARN) for compu ...

  8. HADOOP docker(一):安装hadoop实验集群(略操蛋)

    一.环境准备 1.1.机器规划 主机名    别名    IP     角色 9321a27a2b91 hadoop1 172.17.0.10 NN1 ZK RM 7c3a3c9cd595 hadoo ...

  9. 11.22Daily Scrum

    人员 任务分配完成情况 明天任务分配 王皓南 实现网页上视频浏览的功能.研究相关的代码和功能.979 数据库测试 申开亮 实现网页上视频浏览的功能.研究相关的代码和功能.978 实现视频浏览的功能 王 ...

  10. 《剑指offer》---把数组排成最小的数

    本文算法使用python3实现 1 题目描述:   输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输入数组 $ [3,32,321] $ ,则打印出这 ...