ASP.NET MVC 之View
仅此一文让你明白ASP.NET MVC 之View的显示(仅此一文系列二)
题外话
一周之前写的《仅此一文让你明白ASP.NET MVC原理》受到了广大学习ASP.NET MVC同学的欢迎,于是下定决心准备把它写成一个系列,以满足更多求知若渴的同学们。蒋金楠老师已经在他的《ASP.NET MVC 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时(文章开始部分介绍的代码):
- 从ViewEngines的Engines中获取ViewResultEngine对象,实质是遍历RazorViewEngine和WebFormViewEngine,然后通过它们本身继承VirtualPathProviderViewEngine的成员函数FindView创建ViewResultEngine【从下面的时序图中可以看出,虽然MVC把这个东西藏的很深,但基本都是在父类与子类间传递,结构还算清晰】;
- 通过得到的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>直接继承出来的。当一个ASP.NET MVC网站在编译时,会把所有的视图文件(如cshtml,aspx等)全部编译成基于WebViewPage<TMode>的类,生成的类成员函数ExecutePageHierarchy内部由N多的Response.Write/Response.WriteLiteral组成,实现html的输出。最终将WEB显示出来。
后记
本以为这篇文章很好写,没想到断断续续地写了两天。还是那句话:希望新手看的明白,老手多提意见,谢谢!
接下来一篇会放出View显示的重要组成部分:Model Data的讲解(难道你们看着看着没觉得少了点什么吗?讲了半天流程,实际的数据如何传递?如何显示?),敬请关注!
ASP.NET MVC 之View的更多相关文章
- 返璞归真 asp.net mvc (4) - View/ViewEngine
原文:返璞归真 asp.net mvc (4) - View/ViewEngine [索引页] [源码下载] 返璞归真 asp.net mvc (4) - View/ViewEngine 作者:web ...
- ASP.NET MVC 中 View 的设计
1. 前言 感觉有好长时间没有接触View 了,周末闲来无事,翻翻书桌上的书来回顾回顾ASP.NET MVC中View的相关内容. 2. View概述 View 通过应用程序在Action 中返回 ...
- 预热ASP.NET MVC 的View
ASP.NET MVC 的View 预设是Load on Demand(按需加载),也就是说View 第一次要Render 的时候才会去载入跟编译,这个就会造成一个现象,即使Web 应用程式已经完成启 ...
- TransactionScope事务处理方法介绍及.NET Core中的注意事项 SQL Server数据库漏洞评估了解一下 预热ASP.NET MVC 的VIEW [AUTOMAPPER]反射自动注册AUTOMAPPER PROFILE
TransactionScope事务处理方法介绍及.NET Core中的注意事项 作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/10170712.ht ...
- Asp.Net MVC向视图View传值的三种方法
本文将总结Asp.Net MVC向视图View传值的三种常见的方法: ----------------------------------------------------------------- ...
- 仅此一文让你明白ASP.NET MVC 之View的显示(仅此一文系列二)
题外话 一周之前写的<仅此一文让你明白ASP.NET MVC原理>受到了广大学习ASP.NET MVC同学的欢迎,于是下定决心准备把它写成一个系列,以满足更多求知若渴的同学们.蒋金楠老师已 ...
- Asp.net MVC在View里动态捆绑压缩引用的js
前言 Asp.net MVC 4以上版本多了BundleConfig.RegisterBundles方法,可以把要捆绑的脚本或样式进行捆绑压缩,以减少客户端的请求次数从而提高了客户端的访问速度. 问题 ...
- ASP.NET MVC 前端(View)向后端(Controller)中传值
在MVC中,要把前端View中的值传递给后端Controller, 主要有两种方法 1. 利用Request.Form 或者 Request.QueryString public ActionResu ...
- 【ASP.NET MVC】View与Controller之间传递数据
1 概述 本篇文章主要从操作上简要分析Controller<=>View之间相互传值,关于页面之间传值,如果感兴趣,可参考我另外一篇文章ASP.NET 页面之间传值的几种方式 . Co ...
随机推荐
- Microsoft Build 2015
Microsoft Build 2015 汇总 简要概括(GitHub 完成约 45%): Visual Studio Code Preview Visual Studio 2015 RC Vis ...
- 2014年辛星jquery解读第二节
*************jquery的语法****************** 1.jquery是通过选取HTML元素,而且对选取的元素运行某些操作,从而完毕某些特效的. 2.因此,我们在使用jQu ...
- HDU 2070 Fibbonacci Number
Fibbonacci Number Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...
- IOS中TableView的用法
一.UITableView 1.数据展示的条件 1> UITableView的所有数据都是由数据源(dataSource)提供的,所以要想在UITableView展示数据,必须设置UITable ...
- CSS3实战开发: 纯CSS实现图片过滤分类显示特效
原文:CSS3实战开发: 纯CSS实现图片过滤分类显示特效 各位网友大家好,今天我要带领大家开发一个纯CSS的图片分类显示的网址导航,单纯看标题大家可能有些困惑,依照以往惯例,我先给大家演示一下实际运 ...
- ActiveReports 9实战教程(2): 准备数据源(设计时、运行时)
原文:ActiveReports 9实战教程(2): 准备数据源(设计时.运行时) 在上讲中<ActiveReports 9实战教程(1): 手把手搭建环境Visual Studio 2013 ...
- .net使用cefsharp开源库开发chrome
.net使用cefsharp开源库开发chrome 离上篇写介绍pc端的混合开发和为什么以cefsharp入手研究混合开发已经有好几天,一直忙,抽不出时间继续写怎么搭建cefsharp开发环境.其实没 ...
- 华硕K55DR体验 - 显卡就是坑
朋友拿来电脑,本来他室友已经把他电脑重做完了,但还是卡,非要给我再搞一遍,难道?我就是传说中的大神?咳咳...YY一下,适可而止 华硕K55DR的配置来看,似乎应付CF没什么问题,可是,FPS各种不稳 ...
- Spring MVC 的 研发之路
翻译器:intellij idea 一个.创建spring mvcproject 一个. 二. 三. watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcX ...
- VS2015安装
VS2015安装 Secondary Installer Setup Failed求解决方案 看到微软最近的一系列变化,着实让我等兴奋不已.VS2015下载地址就不说了.先来记录一下微软的几个变化吧. ...