深入理解ASP.NET MVC(6)
Action全局观
在上一篇最后,我们进行到了Action调用的“门口”:
|
1
|
if (!ActionInvoker.InvokeAction(ControllerContext, actionName)) |
在深入研究调用过程的细节前,先有一个总体的认识是很有帮助的。InvokeAction方法大致是按照这样的顺序进行的:
![]()
查找action:MVC内部查找action的方法似乎有点复杂,涉及到一个ActionDescriptor的东西,但是原理上是通过反射,在以后的文章中会有所涉及。
验证和过滤:众所周知的IActionFilter和IAuthorizationFilter在这部分生效,它们在真正执行action之前,事实上对于IResultFilter或IExceptionFilter这样的过滤器是在action执行之后执行的,图中对于这个没有画出。
执行action:真正进入用户代码执行,通过反射调用,调用之前还涉及到复杂的参数提供和绑定,在以后的文章中会涉及。
执行结果:ActionResult在这部起到了关键的作用,ActionResult有多个派生,其中最为常见的就是ViewResult。ActionResult是前面步骤执行的最终“果实”,通过执行ActionResult的ExecuteResult抽象方法,一个HttpRespose被正确的构造好,准备传回客户端。
从ActionResult开始说起
就像上一篇讲到的,我们可以在Controller的Execute方法中直接对HttpContext.Response操作,绕过action;即便我们走了action这一路,仍然可以在action中像下面这样直接操作Response:
|
1
2
3
4
5
6
7
8
9
10
11
|
public class SimpleController : Controller { public void MyActionMethod() { Response.Write("I'll never stop using the <blink>blink</blink> tag"); // ... or ... Response.Redirect("/Some/Other/Url"); // ... or ... Response.TransmitFile(@"c:\files\somefile.zip"); } } |
然而这种方式难以维护,而且难以单元测试,于是MVC框架建议action返回ActionResult,并由框架调用ActionResult的ExecuteResult方法,这类似于设计模式中的command模式。你会看到这种设计模式在这里的运用实在是十分精辟的。
ActionResult是一个十足的抽象类,抽象到不能再抽象了,它定义了唯一的ExecuteResult方法,参数为一个ControllerContext,其中封装了包括HttpContext在内的许多对象,也是重写这个方法唯一的上下文信息:
|
1
2
3
4
5
6
7
8
9
|
namespace System.Web.Mvc { public abstract class ActionResult { public abstract void ExecuteResult(ControllerContext context); }} |
MVC内置了很多实用的ActionResult,如下图:
![]()
我们可以看个简单的实现类RedirectResult是如何实现ExecuteResult的。在这里我发现了我曾经遇到过的一个异常的原因:Child actions are not allowed to perform redirect actions,意思是在子action不允许重定向。
|
1
2
3
4
5
6
7
8
9
10
11
12
|
public override void ExecuteResult(ControllerContext context) { if (context == null) { throw new ArgumentNullException("context"); } if (context.IsChildAction) { throw new InvalidOperationException(MvcResources.RedirectAction_CannotRedirectInChildAction); } string destinationUrl = UrlHelper.GenerateContentUrl(Url, context.HttpContext); context.Controller.TempData.Keep(); context.HttpContext.Response.Redirect(destinationUrl, false /* endResponse */);} |
在这段代码中ExecuteResult的实现相对简单的多,事实上像ViewResult的实现就复杂很多,关于ViewResult将在视图中涉及到。
在Controller中有很多辅助方法便于我们在action中返回需要的ActionResult,下面列出:
Content():返回ContentResult
大家都很少用到这个ActionResult,因为它的基本用法是返回文本,也许下面这段代码可以说服你
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public ContentResult RSSFeed() { Story[] stories = GetAllStories(); // Fetch them from the database or wherever // Build the RSS feed document string encoding = Response.ContentEncoding.WebName; XDocument rss = new XDocument(new XDeclaration("1.0", encoding, "yes"), new XElement("rss", new XAttribute("version", "2.0"), new XElement("channel", new XElement("title", "Example RSS 2.0 feed"), from story in stories select new XElement("item", new XElement("title", story.Title), new XElement("description", story.Description), new XElement("link", story.Url) ) ) ) ); return Content(rss.ToString(), "application/rss+xml"); } |
上面的代码返回了一个RSS。值得注意的是,Content的第二个参数是个contentType(MIME类型,参见www.iana.org/assignments/media-types),如果不指定这个参数将使用text/html的contentType。
事实上我们的action可以返回一个非ActionResult,MVC在执行action的返回结果前,会确保将返回值转换成一个 ActionResult,其中一步,就是对非空和非ActionResult的结果转换成string,并包装成ContentResult:
|
1
2
3
4
5
6
7
8
9
|
protected virtual ActionResult CreateActionResult(ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue) { if (actionReturnValue == null) { return new EmptyResult(); } ActionResult actionResult = (actionReturnValue as ActionResult) ?? new ContentResult { Content = Convert.ToString(actionReturnValue, CultureInfo.InvariantCulture) }; return actionResult;} |
Json():返回JsonResult
Controller的Json方法能返回一个JsonResult,出于安全性的考虑JsonResult只支持POST方式,设置response.ContentType = "application/json";并利用JavaScriptSerializer序列化对象,并返回给客户端。像下面这样使用JsonResult:
|
1
2
3
4
5
6
7
8
9
10
11
12
|
class CityData { public string city; public int temperature; } [HttpPost] public JsonResult WeatherData() { var citiesArray = new[] { new CityData { city = "London", temperature = 68 }, new CityData { city = "Hong Kong", temperature = 84 } }; return Json(citiesArray); } |
JavaScript():返回JavaScriptResult
JavaScript方法实例化一个JavaScriptResult,JavaScriptResult只是简单的设置response.ContentType = "application/x-javascript";
File():返回二进制数据或文件
FileResult是个抽象类,File方法的多个重载返回不同的FileResult:
FilePathResult:直接将一个文件发送给客户端
|
1
2
3
4
5
|
public FilePathResult DownloadReport() { string filename = @"c:\files\somefile.pdf"; return File(filename, "application/pdf", "AnnualReport.pdf"); } |
FileContentResult:返回byte字节给客户端比如图片
|
1
2
3
4
5
|
public FileContentResult GetImage(int productId) { var product = productsRepository.Products.First(x => x.ProductID == productId); return File(product.ImageData, product.ImageMimeType); } |
|
1
|
<img src="<%: Url.Action("GetImage", "Products", new { Model.ProductID }) %>" /> |
FileStreamResult:返回流
|
1
2
3
4
5
6
|
public FileStreamResult ProxyExampleDotCom() { WebClient wc = new WebClient(); return File(stream, "text/html"); } |
PartialView()和View():分别返回PartialViewResult和ViewResult
PartialViewResult和ViewResult十分复杂,涉及到视图,将在以后详细讨论。
Redirect():返回RedirectResult
产生重定向结果,上面已经展示了RedirectResult的实现了。
RedirectToAction(),RedirectToRoute():返回RedirectToRouteResult
RedirectToRouteResult同样是产生跳转的结果,但是它具有“路由表遍历能力”,也就是具有Url outbound的特点,参见深入理解ASP.NET MVC(3)
更多关于ActionResult的派生类的细节,可以参看MVC源码文件。
劳动果实,转载请注明出处:http://www.cnblogs.com/P_Chou/archive/2010/11/26/details-asp-net-mvc-06.html
深入理解ASP.NET MVC(6)的更多相关文章
- 七天学会ASP.NET MVC (一)——深入理解ASP.NET MVC
系列文章 七天学会ASP.NET MVC (一)——深入理解ASP.NET MVC 七天学会ASP.NET MVC (二)——ASP.NET MVC 数据传递 七天学会ASP.NET MVC (三)— ...
- [转载]深入理解ASP.NET MVC之ActionResult
Action全局观 在上一篇最后,我们进行到了Action调用的“门口”: 1 if (!ActionInvoker.InvokeAction(ControllerContext, actionNam ...
- 深入理解ASP.NET MVC Day1
深入理解ASP.NET MVC ASP.NET vs MVC vs WebForms 许多ASP.NET开发人员开始接触MVC认为MVC与ASP.NET完全没有关系,是一个全新的Web开发,事实上 ...
- 七天学会ASP.NET MVC ——深入理解ASP.NET MVC
七天学会ASP.NET MVC (一)——深入理解ASP.NET MVC 系列文章 七天学会ASP.NET MVC (一)——深入理解ASP.NET MVC 七天学会ASP.NET MVC (二) ...
- 深入理解ASP.NET MVC(5)
系列目录 回顾 系列的前4节深入剖析了ASP.NET URL路由机制,以及MVC在此基础上是如何实现Areas机制的,同时涉及到inbound和outbound很多细节部分.第2节中提到MvcRout ...
- 深入理解ASP.NET MVC(目录)
学ASP.NET MVC2有一段时间了,也针对性的做了个练习.感觉这个框架还是不错的,所以决定要深入系统的学习一下.看到这样一本书: 作者博客:http://blog.stevensanderson. ...
- 七天学会ASP.NET MVC (一)——深入理解ASP.NET MVC 【转】
http://www.cnblogs.com/powertoolsteam/p/MVC_one.html 系列文章 七天学会ASP.NET MVC (一)——深入理解ASP.NET MVC 七天学会A ...
- [转载] ASP.NET MVC (一)——深入理解ASP.NET MVC
个人认为写得比较透彻得Asp.net mvc 文章,所以转载过来,原文链接在最后: ASP.NET vs MVC vs WebForms 许多ASP.NET开发人员开始接触MVC认为MVC与ASP.N ...
- 理解ASP.NET MVC的路由系统
引言 路由,正如其名,是决定消息经由何处被传递到何处的过程.也正如网络设备路由器Router一样,ASP.NET MVC框架处理请求URL的方式,同样依赖于一张预定义的路由表.以该路由表为转发依据,请 ...
随机推荐
- JAVA测试编程
本周我们上JAVA课的时候进行了一次测试,本次测试以模拟中国工商银行自助机ATM的功能为大致要求,要求我们进行编写调试,以求达到试题要求. 测试要求我们能模拟ATM的功能设计,当用户插卡后显示,输入密 ...
- 3--Selenium环境准备--Eclipse 引入 selenium-server包
1.下载selenium-server包 selenium-server-standalone包是Seleniumd的核心jar包,其中包含了各种元素定位和调用浏览器的方法.下载jar包后,在ID ...
- 【Python】混合驱动实例
keywords2.txt: get||ie||{urls.txt} get||chrome||http://www.iciba.com main.py: from selenium import w ...
- Java技术体系
Shell 解释型编程语言(脚本语言都是解释型语言) Shell通过解释器/bin/bash 解释,运行在进程中 Java 编译型解释型语言(先编译再解释) Java通过编译器转换成字节码语言,再用过 ...
- tableView 分割线的处理
有时候根据UI设计图的需要我们需要对原生的TableView分割线做靠左,靠右的操作 在下面这个方法中实现即可. - (void)tableView:(UITableView *)tableView ...
- 20165228 2017-2018-2 《Java程序设计》第3周学习总结
20165228 2017-2018-2 <Java程序设计>第3周学习总结 教材学习内容总结 编程语言 面向机器语言:机器能直接识别的语言, 其指令由特定的二进制码表示. 其中汇编语言是 ...
- PHP目前比较常见的五大运行模式SAPI(转)
运行模式 关于PHP目前比较常见的五大运行模式: 1)CGI(通用网关接口/ Common Gateway Interface) 2)FastCGI(常驻型CGI / Long-Live CGI) 3 ...
- Git版本退回和修改
首先我们来看看我们的第一个版本: 我的git文件如下: 那我们来修改一下这个文件 然后提交 那我们来查看一下提交的记录:使用git log 当我们使用 git log --pretty=oneline ...
- linux命令行总结给自己看的版本
复制 cp -r /src /dst 查看硬盘容量 df -h 重命名: mv /原来的 /现在的
- 二叉树求逆序对(伪AC 23333)
成链的时候 是最坏情况 O(n^2)的复杂度呢! 按照输入的数据 一个一个的插入建树 然后维护左右儿子的个数 (我们规定, 左儿子 小于 父亲 右儿子大于父亲) 往左走 说明存在逆序对 逆序对的 ...