《ASP.NET MVC4 WEB编程》学习笔记------.net mvc实现原理ActionResult/View

时间:2022-12-08 10:39:42
ActionResult
ActionResult是Action的返回结果。ActionResult 有多个派生类,每个子类功能均不同,并不是所有的子类都需要返回视图View,有些直接返回流,有些返回字符串等。我们来看一下ActionResult派生类关系图
《ASP.NET MVC4 WEB编程》学习笔记------.net mvc实现原理ActionResult/View
具体看一下每个类的功能,由于MSDN的示意图太简单不能完全表现所有的子类功能
类名 抽象类 父类 功能
 ActionResult  abstract  Object 顶层父类
ContentResult     根据内容的类型和编码,数据内容.通过Controller的Content方法返回
EmptyResult     返回空结果
FileResult abstract   写入文件内容,具体的写入方式在派生类中.
FileContentResult   FileResult 通过 文件byte[] 写入Response 返回客户端,Controller的File方法
FilePathResult   FileResult 通过 文件路径 写入Response 返回客户端,Controller的File方法
FileStreamResult   FileResult 通过 Stream 写入Response 返回客户端,Controller的File方法
HttpUnauthorizedResult     抛出401错误
JavaScriptResult     返回javascript文件
JsonResult     返回Json格式的数据
RedirectResult     使用Response.Redirect重定向页面
RedirectToRouteResult     根据Route规则重定向页面
ViewResultBase abstract   调用IView.Render() 返回视图,两个常用属性ViewData,TempData
PartialViewResult   ViewResultBase 调用父类ViewResultBase 的ExecuteResult方法. 
重写了父类的FindView方法. 
寻找用户控件.ascx文件
ViewResult   ViewResultBase

调用父类ViewResultBase 的ExecuteResult方法. 
重写了父类的FindView方法. 
寻找视图页面(aspx,cshtml或自定义视图)

Controller的View()方法默认封装ViewResult返回结果

简单的列几种写法,都是Controller已经封装好的
 public ActionResult ShowContent()
{
return Content("测试ContentResult方法"); //默认封装ContentResult文本返回
} public ActionResult Index(UserVO userVo)
{
return View(); //默认封装ViewResult返回
} public ActionResult DownLoadFile(string fileName)
{
return File(Server.MapPath(@"/Images/view.jpg"), @"image/gif");
} public ActionResult ToOther(string fileName)
{
return Redirect(@"http://localhost:1847/Menu/ShowContent");
}
当然你可以自己实现每种的类型返回,而不是通过Controller的方法返回。这个环节最重要的问题,当Action返回ActionResult后,这个ActionResult是如何工作的?ActionResult只有一个抽象方法 ExecuteResult ,当ActionResult实例被返回后,Controller执行器ControllerActionInvoker的InvokeAction方法在处理完IActionFilter之后调用了这段代码InvokeActionResultWithFilters(controllerContext, filterInfo.ResultFilters, postActionContext.Result);
看后两个参数,一个是IResultFilter过滤器,一个是Action返回的Result。该方法对返回ActionResult进行前置拦截后,接着调用ActionResult的ExecuteResult方法去处对应的响应业务(返回视图,或字符串,文件流等),最后又对ActionResult后置拦截了一次。调用棧比较深
 
//1---------------------------------
protected virtual ResultExecutedContext InvokeActionResultWithFilters(ControllerContext controllerContext, IList<IResultFilter> filters, ActionResult actionResult) {
ResultExecutingContext preContext = new ResultExecutingContext(controllerContext, actionResult);
//InvokeActionResult 做为委托被前置与后置包围了
Func<ResultExecutedContext> continuation = delegate {
InvokeActionResult(controllerContext, actionResult);
return new ResultExecutedContext(controllerContext, actionResult, false /* canceled */, null /* exception */);
}; // need to reverse the filter list because the continuations are built up backward
Func<ResultExecutedContext> thunk = filters.Reverse().Aggregate(continuation,
(next, filter) => () => InvokeActionResultFilter(filter, preContext, next));
return thunk();
}
//2--------------------------------------------
internal static ResultExecutedContext InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func<ResultExecutedContext> continuation) {
filter.OnResultExecuting(preContext); //前置拦截----------------------------------------
if (preContext.Cancel) {
return new ResultExecutedContext(preContext, preContext.Result, true /* canceled */, null /* exception */);
} bool wasError = false;
ResultExecutedContext postContext = null;
try {
postContext = continuation(); //ActionResult的ExecuteResult的调用环节------------------------------------------
}
catch (ThreadAbortException) {
// This type of exception occurs as a result of Response.Redirect(), but we special-case so that
// the filters don't see this as an error.
postContext = new ResultExecutedContext(preContext, preContext.Result, false /* canceled */, null /* exception */);
filter.OnResultExecuted(postContext); //出错了,后置拦截----------------------------------
throw;
}
catch (Exception ex) {
wasError = true;
postContext = new ResultExecutedContext(preContext, preContext.Result, false /* canceled */, ex);
filter.OnResultExecuted(postContext);
if (!postContext.ExceptionHandled) {
throw;
}
}
if (!wasError) {
filter.OnResultExecuted(postContext); //后置拦截----------------------------------------------
}
return postContext;
}
//3------------------------------------------------------------------
protected virtual void InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult) {
actionResult.ExecuteResult(controllerContext);
}
注释的地方注意看一下,InvokeActionResult 是调用ActionResult.ExecuteResult的方法,被做为委托放到IResultFilter前后拦截法中间执行。Controller的执行器ControllerActionInvoker 这几个环节的调度者。再看一下ActionResult.ExecuteResult方法的业务,挑选个有代表性的子类实现的业务贴上来,
FileResult基类 的ExecuteResult,但又调用了WriteFile方法,这个方法又下放到子类中实现了
ublic override void ExecuteResult(ControllerContext context) {
if (context == null) {
throw new ArgumentNullException("context");
} HttpResponseBase response = context.HttpContext.Response;
response.ContentType = ContentType; if (!String.IsNullOrEmpty(FileDownloadName)) {
// From RFC 2183, Sec. 2.3:
// The sender may want to suggest a filename to be used if the entity is
// detached and stored in a separate file. If the receiving MUA writes
// the entity to a file, the suggested filename should be used as a
// basis for the actual filename, where possible.
string headerValue = ContentDispositionUtil.GetHeaderValue(FileDownloadName);
context.HttpContext.Response.AddHeader("Content-Disposition", headerValue);
} WriteFile(response);
}
我们挑选FileStreamResult子类的WriteFile方法看看
protected override void WriteFile(HttpResponseBase response) {
// grab chunks of data and write to the output stream
Stream outputStream = response.OutputStream;
using (FileStream) {
byte[] buffer = new byte[_bufferSize]; while (true) {
int bytesRead = FileStream.Read(buffer, , _bufferSize);
if (bytesRead == ) {
// no more data
break;
} outputStream.Write(buffer, , bytesRead);
}
}
}
整个过程看下来FileStreamResult的ExecuteResult 将文件流写入HttpResponse中返回到客户端,而并不是返回视图。再看一下ViewResult的ExecuteResult的业务,这个业务是在父类的中实现的
ViewResultBase的ExecuteResult业务,ViewResultBase还有两个重要的性ViewData,TempData是在Acion返回的时候封装好的。
public override void ExecuteResult(ControllerContext context) {
if (context == null) {
throw new ArgumentNullException("context");
}
if (String.IsNullOrEmpty(ViewName)) {
ViewName = context.RouteData.GetRequiredString("action");
} ViewEngineResult result = null; if (View == null) {
result = FindView(context);
View = result.View;
} TextWriter writer = context.HttpContext.Response.Output;
ViewContext viewContext = new ViewContext(context, View, ViewData, TempData, writer);
View.Render(viewContext, writer); if (result != null) {
result.ViewEngine.ReleaseView(context, View);
}
}
 
先根据上下文中的路由+Action名找到对应的IView,然后调用IView的Render会出视图写入context.HttpContext.Response.Output返回到客户端。

《ASP.NET MVC4 WEB编程》学习笔记------.net mvc实现原理ActionResult/View的更多相关文章

  1. Asp&period;net MVC4高级编程学习笔记-视图学习第一课20171009

    首先解释下:本文只是对Asp.net MVC4高级编程这本书学习记录的学习笔记,书本内容感觉挺简单的,但学习容易忘记,因此在边看的同时边作下了笔记,可能其它朋友看的话没有情境和逻辑顺序还请谅解! 一. ...

  2. Asp&period;net MVC4高级编程学习笔记-视图学习第三课Razor页面布局20171010

    Razor页面布局 1)  在布局模板页中使用@RenderBody标记来渲染主要内容.比如很多web页面说头部和尾部相同,中间内容部分使用@RenderBody来显示不同的页面内容. 2)  在布局 ...

  3. Asp&period;net MVC4高级编程学习笔记-模型学习第四课基架与模型绑定20171027

    MVC模型 一.构建基架. MVC中的基架可以为应用程序提供CURD各种功能生成所需要的样板代码.在添加控制器的时候可以选择相应的模板以及实体对象来生成相应的模板代码. 首先定义一个模型类如下所示: ...

  4. Asp&period;net MVC4高级编程学习笔记-模型学习第五课MVC表单和HTML辅助方法20171101

    MVC表单和HTML辅助方法 一.表单的使用. 表单中的action与method特性.Action表示表单要提交往那里,因此这里就有一个URL.这个URL可以是相对或绝对地址.表单默认的method ...

  5. ASP&period;NET Core Web开发学习笔记-1介绍篇

    ASP.NET Core Web开发学习笔记-1介绍篇 给大家说声报歉,从2012年个人情感破裂的那一天,本人的51CTO,CnBlogs,Csdn,QQ,Weboo就再也没有更新过.踏实的生活(曾辞 ...

  6. Go web编程学习笔记——未完待续

    1. 1).GOPATH设置 先设置自己的GOPATH,可以在本机中运行$PATH进行查看: userdeMacBook-Pro:~ user$ $GOPATH -bash: /Users/user/ ...

  7. 《ASP&period;NET MVC4 WEB编程》学习笔记------Web API

    本文截取自情缘 1. Web API简单说明 近来很多大型的平台都公开了Web API.比如百度地图 Web API,做过地图相关的人都熟悉.公开服务这种方式可以使它易于与各种各样的设备和客户端平台集 ...

  8. 《ASP&period;NET MVC4 WEB编程》学习笔记------Web API 续

    目录 ASP.NET WEB API的出现缘由 ASP.NET WEB API的强大功能 ASP.NET WEB API的出现缘由 随着UI AJAX 请求适量的增加,ASP.NET MVC基于Jso ...

  9. 《ASP&period;NET MVC4 WEB编程》学习笔记------Model模型绑定

    本文转载自haiziguo Asp.net mvc中的模型绑定,或许大家经常用,但是具体说他是怎么一回事,可能还是会有些陌生,那么,本文就带你理解模型绑定.为了理解模型绑定,本文会先给出其定义,然后对 ...

随机推荐

  1. 学习SQL的点点滴滴(四)-UPDATE小计

    1.更新tb_card中c_customer字段的值等于tb_customer表中c_no的值 update tb_card set c_customer=ct.c_no from tb_custom ...

  2. android 上手维修设备和推断启动服务

    下载链接:http://download.csdn.net/detail/a123demi/7511823 我们经常在开发的时候,通过获取系统已启动的服务来推断该server是否还须要再启动. 而本文 ...

  3. java对String进行sha1加密

    1.使用apache的codec jar包对string进行加密,先下载并引入jar包: http://commons.apache.org/proper/commons-codec/ 2.生成: S ...

  4. c语言第五次作业--函数

    一.PTA实验作业 题目1.使用函数输出一个整数的逆序数 1.本题PTA提交列表 2.设计思路 1.int mod,rever:分别表示余数和返回的数 2.while(number%10 || num ...

  5. &lpar;NO&period;00003&rpar;iOS游戏简单的机器人投射游戏成形记&lpar;六&rpar;

    为什么要将手臂移动的代码单独放在一个方法中? 其实这里是多次重构之后的版本.原来的移动代码是放在touchMoved方法里的.后来发现除了触摸手臂移动方式外,还要实现触摸屏幕移动手臂这第二种方式. 所 ...

  6. HBuilderx中编译sass文件

    安装scss/sass编译插件 工具 -> 插件安装 -> scss/sass编译插件 将sass编译成css 新建scss文件,编写完成后,(右键scss文件 -> 外部命令/插件 ...

  7. Android开发 - 更&quot&semi;聪明&quot&semi;的申请权限方式

    在Android6.0以后,很多权限需要动态申请,只有在用户点同意后,我们才能使用对应API,因此,正确申请权限就显得很重要. 常用方式 通常我们使用这种方式来判断权限状态: private stat ...

  8. linux中Java项目占用cpu、内存过高时的排查经历

    一.使用top命令查看占用高资源的java项目的进程ID(pid): top 二.查看该进程中的线程所占用资源的情况:top -Hp pid 三.查看该线程对应的16进制:printf %x 1112 ...

  9. 素数问题练习&lowbar;HDOJ1262

    HDOJ1262_寻找素数对 和上一篇博客一样的解法,将10000以内的所有素数求出即可解题. #include<stdio.h> #include<stdlib.h> #in ...

  10. LeetCode--003--无重复字符的最长子串

    问题描述: 给定一个字符串,找出不含有重复字符的最长子串的长度. 示例 1: 输入: "abcabcbb" 输出: 3 解释: 无重复字符的最长子串是 "abc&quot ...