ActionResult
ActionResult是Action的返回结果。ActionResult 有多个派生类,每个子类功能均不同,并不是所有的子类都需要返回视图View,有些直接返回流,有些返回字符串等。我们来看一下ActionResult派生类关系图
具体看一下每个类的功能,由于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.net MVC4高级编程学习笔记-视图学习第一课20171009

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

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

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

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

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

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

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

  5. ASP.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.NET MVC4 WEB编程》学习笔记------Web API

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

  8. 《ASP.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.NET MVC4 WEB编程》学习笔记------Model模型绑定

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

随机推荐

  1. NumberFormat类的用法

    NumberFormat.getInstance()方法返回NumberFormat的一个实例(实际上是NumberFormat具体的一个子类,例如DecimalFormat), 这适合根据本地设置格 ...

  2. c# 多线程 调用带参数函数

    线程操作主要用到Thread类,他是定义在System.Threading.dll下.使用时需要添加这一个引用.该类提供给我们四个重载的构造函数(以下引自msdn).       Thread (Pa ...

  3. 通过smtp协议简单实现邮件发送

    使用到的类: ①SmtpClient--发送邮件的类(using System.Net.Mail;) ②MailMessage--初始化邮件的类 ③ NetworkCredential--身份验证的类 ...

  4. [HNOI2010]BOUNCE 弹飞绵羊

    题目描述 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系 ...

  5. PHP邮件注入攻击技术

    1. 简介 如 今,互联网的使用急剧上升,但绝大多数互联网用户没有安全知识背景.大多数的人都会使用互联网通过邮件Email的方式和他人进行通信.出于这个原因,大 多数网站允许他们的用户联系他们,向网站 ...

  6. 用多态来实现U盘,Mp3,移动硬盘和电脑的对接,读取写入数据。

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  7. js 对象方法、类方法、原型方法的区别;私有属性、公有属性、公有静态属性的区别

    <html> <head> <meta http-equiv="Content-Type" content="text/html; char ...

  8. IIS负载均衡-Application Request Route详解第四篇:使用ARR实现三层部署架构(转载)

    IIS负载均衡-Application Request Route详解第四篇:使用ARR实现三层部署架构 系列文章链接: IIS负载均衡-Application Request Route详解第一篇: ...

  9. SQL2005删除复制数据库的发布与订阅的方法(转载)

    SQL2005删除复制数据库的发布与订阅的方法 --在测试环境中恢复从正式数据库服务器 上备份下来的bak文件后,正式环境里数据库复制的发布.订阅也被带进来了,结果恢复的数据库无法更改表结构,直接删除 ...

  10. C# 汉字转拼音

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Comm ...