白话学习MVC(九)View的呈现一

简介:

一、概述

  本节来看一下ASP.NET MVC【View的呈现】的内容,View的呈现是在Action执行之后进行,Action的执行生成一个ActionResult,【View的呈现】的功能就是:通过InvokeActionResult方法对【Action的执行】中生成的ActionResult进行处理。(ActionResult泛指那些继承自抽象类System.Web.Mvc.ActonResult的类的实例)

  为了会纵观【View的呈现】在全局中的位置,下面我们再来回顾下处理请求的整个流程:在此系列开篇的时候介绍了MVC的生命周期 , 对于ASP.NET和ASP.NET MVC,都是将相应的类的方法注册到HttpApplication事件中,通过事件的依次执行从而完成对请求的处理。而针对MVC,请求是先 经过路由系统,然后由一个MvcHandler来处理的,当请求到来时,执行此MvcHandler的ProcessRequest方法(因为已将 MvcHandler类的ProcessRequest方法注册到HttpApplication的事件中,所以事件的执行就触发了此方法),下图就是一个简要的执行过程!

1
2
3
4
5
6
7
public  class  ControllerActionInvoker : IActionInvoker
{
     protected  virtual  void  InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
     {
         actionResult.ExecuteResult(controllerContext);
     }
}

  整个过程大致经过【Controller的激活】-->【Action的执行】-->【View的呈现】,由上图可知,【View的呈现】是由ControllerActionInvoker类中的InvokeActionResult方法来触发的!

 二、ActionResult的创建

   概述中提到,【View的呈现】的功能就是:通过InvokeActionResult方法对【Action的执行】中生成的ActionResult进行处理。即:ActionResult是在【Action的执行】中创建的,创建方式有:

  • 请求没有通过Action的过滤器时,在过滤器的方法中创建一个ActionResult,将其当作最终的ActionResult,进行View的呈现
  • 请求通过所有过滤器,将Action方法返回的ActionResult当作最终的ActionResult,进行View的呈现。
    注:在Action方法中其实调用Controller类中的方法来进行创建ActionResult实例的,如:return Content("OK");等同于return new ContentResult(){ Content="OK"};

例、自定义个Action过滤器,当没有通过时按照过滤器中定义的ActionResult进行View的呈现,具体执行过程下一部分介绍!

  View Code

三、View呈现过程分析

  ASP.NET MVC的【View的呈现】其实就是执行ActonResult的ExcuteResult方法!而接下来我们介绍的就是这个ExcuteResult方法触发了那些操作!!!在介绍之前我们先来看看微软提供了那些ActionResult!(ActionResult泛指那些继承自System.Web.Mvc.ActionResult的类)

  基类System.Web.Mvc.ActionResult
  • EmptyResult
  • ContentResult
  • FileResult
  • JavaScriptResult
  • JsonResult
  • HttpStatusCodeResult
  • RedirectResult
  • RedirectToRouteResult
  • ViewResult

  在ASP.NET MVC 的【Action的执行】中创建以上任意一个ActionResult对象,并执行该对象的ExcuteResult方法,从而进行【View的呈现】。这里的最后一项ViewResult比较特殊,它的处理流程相对复杂,涉及到Razor引擎什么的,之后详细介绍!

 下面就来看一些以上ActionResult的源码,了解下【View的呈现】如何实现!

1、EmptyResult

  由EmptyResult源码可见,其ExecuteReuslt方法什么都没做,也就是该ActionReuslt的【View的呈现】部分不做任何操作,那么此流程也就执行完毕。再看概述中的图可知,接下来进行【对TempData再一次处理】-->【释放Controller对象】,之后再继续HttpApplication其他的事件,包括对Session的处理、缓存的处理、对请求的返回等。

 2、ContentResult

  ContentResult用于将字符串响应给客户端!

  上述context.HttpContext.Response得到的是一个HttpResponseWrapper类型的对象response,该对象内有一个HttpResponse类型的私有变量_httpResponse,对于该HttpResponseWrapper对象的属性和方法其实都是执行私有变量_httpResponse对应的属性和方法!
由于HttpResponseWrapper对象属性和方法都是对私有变量_httpResponse的相关操作,而查看HttpResponseWrapper类部分源代码,_httpResponse变量是通过构造函数赋值的,而该构造函数的参数值是怎么来的呢?是在HttpApplication事件之前,通过HttpRuntime类创建请求上下文HttpContext对象时,又触发创建了HttpResponse对象并赋值到请求上下文HttpContext对象的一个私有变量中保存着的!
又由于HttpResponse对象的属性和方法又都是对私有变量_writer的相关操作,再看HttpResponse类的源代码,它的Write的方法其实是执行其TextWriter类型的私有变量_writer的Write方法,而该私有变量_writer是怎么来的呢?是在HttpApplication事件之前,通过HttpRuntime类创建请求上下文HttpContext对象时,触发创建了HttpResponse对象,之后又初始化HttpResponse对象的_writer字段为一个HttpWriter对象。
最终,执行HttpWriter对象的Write方法,根据ContentType定义的媒体类型和ContentEncoding定义的编码方法将字符串发送到 HTTP 输出流。ContentType定义的是MIME类型(默认为”text/html"),ContentEncoding定义的编码方式(默认是操作系统的当前 ANSI 代码页的编码System.Text.Encoding.Default)。

  HttpResponseWrapper
  HttpResponse
  HttpWriter

在ASP.NET MVC 的Controller类中提供了以下三个创建ContentResult的重载,当然也可以直接在Action中创建ContentReuslt对象并作为方法的返回值。

  Controller

扩展:请求上下文HttpContext、HttpResponse、HttpRequest创建流程
  当请求到达IIS,IIS根据请求的后缀名判断是否加载aspnet_isapi.dll,一旦工作进程加载了aspnet_isapi.dll,就会加载IsapiRuntime,被加载的IsapiRuntime会接管Http请求,之后IsapiRuntime执行其方法ProcessRequest(IntPtr ecb, int iWRType),该方法实现从ISAPI扩展控制块(ECB)中获取当前Http请求相关信息并封装到IsapiWorkrRequest对象中。然后将该对象传递给HttpRuntime,通过该类中的ProcessRequestInternal()方法创建HttpContext类实例,进入ProcessRequestInternal方法之后,内部触发一系列的方法,最终创建一个HttpContent实例(可通过HttpContent.Current获取到这个实例),且该实例会在整个生命周期内存活。创建HttpContext对象时,同时也创建了HttpRequest和HttpResponse对象,并赋值到私有字段中,通过公有属性去获取这两个对象。

  之后HttpRuntime会向HttpApplicationFactory类 提出请求,要求返回一个HttpApplication对象,HttpApplicationFactory在收到请求之后会检查是否有已经存在并且空闲的对象,如果有就取出一个HttpApplication对象返回给HttpRuntime类,如果没有,则要创建一个给HttpRuntime。

  ISAPIRuntime
  HttpRuntime
  HttpContext

 3、FileResult

  FileResult用于将某个物理文件的内容响应给客户端!

  对于FileResult,具有一个表示媒体类型的只读属性ContentType,该属性在构造函数中被初始化。当我们基于某个物理文件创建相应的FileReuslt对象的时候应该根据文件的类型指定该媒体类型属性,例如:目标文件是.jpg图片,那么对应的媒体类型应该是“image/jpeg”;对于一个.pdf文件,则采用“application/pdf”。

  对于FileResult,还具有一个表示下载文件名的属性FileDownloadName,如果该属性没有指定或者设置的值为null,则会按照内联的方式利用浏览器直接打开响应的文件,否则会以附件的形式被下载并且文件名为属性FileDownloadName的值。(查看FileResult源码可知,内联和附件的区别是响应是否包含“Content-Disposition”报头)
  FileReult仅仅是一个抽象类,对于文件内容的输出实现在抽象方法WriteFile方法中。FileResult有三个派生类实现了WriterFile方法分别是:

  FileContentResult
  FileStreamResult
  FilePathResult

  以上的三个继承自FileResult的类,最终都是通过 文件的字节数组 的形式发送到Http输出流,不同的是作为开发者其起始点不一,FileContentResult传入字节数组然后将内容写入当前Http响应的输出流,FileStreamReuslt传入数据流,之后内部存入字节数组再将内容写入当前Http响应的输出流,FilePathResult传入文件地址,之后内部读取文件并存入字节数组再将内容写入当前Http响应的输出流。

 在ASP.NET MVC 的Controller类中提供了创建以上三个FileResult派生类的对象的重载,当然也可以直接在Action中创建相应的FileReuslt对象并作为方法的返回值。

  Controller

 4、JavaScriptResult

  在后台动态的以字符串形式传入一段JavaScript脚本,并作为请求的响应使得脚本在客户端被执行!

  通过JavaScriptResult源码可以看出,其输出方式和ContentResult相同,不同的只是在JavaScriptResult中内部指定了输出的媒体类型为“application/x-javascript”(也可以是“text/javascript”),而我们也可以通过设置ContentResult的输出媒体类型来实现与JavaScriptResult相同的功能!

  在ASP.NET MVC 的Controller类中提供了创建JavaScriptResult对象的方法,当然也可以直接在Action中创建JavaScriptResult对象并作为方法的返回值。

  Controller

5、JsonResult

  JsonResutl用于以Json的格式返回响应的数据!

1
2
3
4
5
public  enum  JsonRequestBehavior
{
     AllowGet,
     DenyGet,
}

  对于JsonResult,其构造函数中为属性JsonRequestBehavior设置了一个枚举值DenyGet,该枚举值的作用就是拒绝对GET请求进行响应,也就是默认情况下,对于Json格式的数据响应,Get请求是不予支持的。如果想要支持Get请求,可以显示的设置JsonRequestBehavior属性的枚举值为AllowGet。
  对于JsonResult,其默认的媒体类型为“application/json”。
  JsonResult就是将CLR对象到Json格式字符串的序列化过程,而上述源码中的object类型的Data属性就是用来获取或设置原始的CLR对象,原始的CLR对象通过JavaScriptSerializer类的Serialize方法的序列化,将CLR对象转换成Json格式的字符串。在JavaScriptSerializer类在对CLR对象进行序列化时还可以对过程进行一些设置,即:MaxJsonLength(Json字符串的最大长度)、RecursionLimit(序列化类时递归的最大深度)。可以在JsonResult对应的属性中设置,也可以在WebConfig中设置。更多设置

1
2
3
4
5
6
7
8
9
<configuration>
   <system.web.extensions>
     <scripting>
       <webServices>
         <jsonSerialization maxJsonLength= "5000" />
       </webServices>
     </scripting>
   </system.web.extensions>
</configuration>

  在ASP.NET MVC 的Controller类中提供了一下创建JsonResult对象的方法,当然也可以直接在Action中创建JsonResult对象并作为方法的返回值。

  Controller

6、HttpStatusCodeResult

  HttpStatusCodeResult用于返回对Http请求响应状态的代码和一个可选的状态描述!

  HttpStatusCodeResult为Http的响应头设置状态代码和状态描述,设置时,可以通过构造函数传入值也可以通过给属性赋值来操作。对于HttpStatustCodeResult的构造函数中HttpStatusCode类型的参数,它是一个枚举类型,其中包含了众多Http响应头状态。
  值得一说的是,如果我们采用Visual StudioDvelopment Server作为Web应用的宿主,通过HttpStatusCodeResult的StatusDescription属性设置的状态描述信息不会反映在Http响应中,只有采用IIS作为宿主才会真正将此信息写入响应消息。

  HttpStatusCode

  ASP.NET MVC中有两个继承自HttpStatusCodeResult的类,即:HttpNotFoundResult和AuthorizeAttribute,用于指定特定相应状态和状态描述,本质上还是执行HttpStatusCodeResult来完成,只不过在内部为HttpStatuCodeResult指定了响应状态,分别是404、401。

  HttpNotFoundResult
  HttpUnauthorizedResult

7、RedirecteResult

  RedirectResult用于实现针对某个地址的重定向!

  对于RedirectResult,可以定义暂时重定向(302重定向)和永久重定向(301重定向),两种重定向的不同作用主要体现在SEO上,搜索引擎会使用永久重定向目标地址更新自己的索引,而暂时重定向则不会。另外,永久重定向是在ASP.NET 4之后引进的,在之前如果想要实现永久重定向的话,需要自己来设置Http响应状态码为301。
  对于UrlHelper.GenerateCotentUrl方法,用来处理Url。当定义的Url为相对地址时,如:~/xxx/xxx,该方法会利用请求上下文来补全地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public  static  string  GenerateContentUrl( string  contentPath, HttpContextBase httpContext)
{
     if  ( string .IsNullOrEmpty(contentPath))
     {
         throw  new  ArgumentException(MvcResources.Common_NullOrEmpty,  "contentPath" );
     }
     if  (httpContext ==  null )
     {
         throw  new  ArgumentNullException( "httpContext" );
     }
     if  (contentPath[0] ==  '~' )
     {
         return  PathHelpers.GenerateClientUrl(httpContext, contentPath);
     }
     return  contentPath;
}

  对于ASP.NET MVC的Controller类中定义了一下几个方法来创建RedirectResult,然也可以直接在Action中创建RedirectResult对象并作为方法的返回值。

  Controller

8、RedirectToRoutResult

  RedirectToRouteResult用于将路由信息中的Controller和Action拼接成Url,再进行跳转!

  RedirectToRouteResult和RedirectResult都是实现重定向,只不过RedirectToRouteResult的跳转地址是通过路由信息中的Controller和Action的拼接来完成的,其他均和RedirectResult相同!

  ASP.NET MVC在Controller类中定义了几个方法用于创建RedirectToRouteResult对象,当然也可以直接在Action中创建RedirectToRouteResult对象并作为方法的返回值。

  Controller

9、ViewResult

  ViewResult内容包含了:PartialViewResult和ViewResult。ViewResult将视图页的内容响应给客户端,而PartialViewResult称分部视图,其响应请求时不输出那写html、head、body等标签,只是将分部视图中内容返回!由于ViewResult和PartialViewResult在进行【View呈现】的过程大致相同,所以此处就只针对ViewResult进行详细解读,而PartialViewRsult详细过程将不再敖述。(分部视图的更多信息:关于如何PartialViewResult的使用

  ViewResultBase
  ViewResult
  PartialViewResult

Controller类中定义的创建ViewResult和PartialViewResult对象的方法:

  Controller

ViewResult进行呈现的大致流程为:

  • 获取视图引擎,默认有两个:ASPX引擎、Razor引擎。
  • 根据视图页名称,通过视图引擎去检查是否存在对应的视图页,如果存在,则创建视图对象。如果不存在,则将所有视图引擎寻找过的路径作为异常返回。
  • 创建视图对象之后,处理视图页中的内容(先处理_ViewStart.cshtml,之后再处理相应的试图页)。例如:TempData、Html.XXX等。
  • 视图页内容处理完毕之后,就将视图内容作为响应返回给客户端。

  对于上述流程中的第三步中,创建视图对象之后,通过它来对视图页进行处理。在对处理视图页时,首先要处理_ViewStart.cshtml文件(相当与asp.net中的Page_Load方法),之后再去处理请求的试图页。例如:如果在~/View/HomeController目录下创建一个_ViewStart.cshtml文件,那么之后当请求HomeController目录下的任意视图页时,都会先执行_ViewStart.cshtml,如果再在~/View目录下创建一个_ViewStart.cshtml的话,那么在请求HomeController目录下的任意视图页时,那么两个_ViewStart.cshtml都会先执行,且顺序为:先~/View目录下后~/View/HomeController目录下的_ViewStart.cshtml。

由于ViewResult的详细过程涉及内容较多,所以将另写一篇博文来对其进行详细分析:《白话学习MVC(十)View的呈现二》

 


本文转自武沛齐博客园博客,原文链接:http://www.cnblogs.com/wupeiqi/p/3461823.html,如需转载请自行联系原作者

目录
相关文章
|
16天前
|
设计模式 存储 前端开发
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
|
4月前
|
XML 前端开发 应用服务中间件
Cannot resolve MVC View解决方案
Cannot resolve MVC View解决方案
130 0
Cannot resolve MVC View解决方案
|
4月前
|
前端开发 Java 应用服务中间件
快速上手:探索Spring MVC的学习秘籍!
快速上手:探索Spring MVC的学习秘籍!
|
4月前
|
前端开发 JavaScript Java
springboot 出现 Cannot resolve MVC View ‘index‘ 问题解决办法,前后端不分离项目前端文件存放位置,已经如何访问
springboot 出现 Cannot resolve MVC View ‘index‘ 问题解决办法,前后端不分离项目前端文件存放位置,已经如何访问
144 0
|
4月前
|
前端开发 Java 数据库
MVC架构学习归纳总结(小傅哥の码场 学习专栏)
MVC架构学习归纳总结(小傅哥の码场 学习专栏)
21 0
|
6月前
|
设计模式 前端开发 Java
一篇文章让使你的Spring Mvc学习入门,还不来了解吗?
一篇文章让使你的Spring Mvc学习入门,还不来了解吗?
|
6月前
|
监控 前端开发 Java
学习 [Spring MVC] 的JSR 303和拦截器,提高开发效率
学习 [Spring MVC] 的JSR 303和拦截器,提高开发效率
33 0
|
设计模式 监控 前端开发
Spring MVC学习(五)-------处理器拦截器详解
Spring MVC学习(五)-------处理器拦截器详解
Spring MVC学习(五)-------处理器拦截器详解
|
前端开发 网络协议 网络架构
Gin从入门到精通—搭建MVC项目结构学习路由配置
Gin从入门到精通—搭建MVC项目结构学习路由配置
354 0
|
XML JSON 前端开发
Spring 全家桶之 Spring Web MVC(三)- View & ViewResolve
Spring 全家桶之 Spring Web MVC(三)- View & ViewResolve
Spring 全家桶之 Spring Web MVC(三)- View & ViewResolve