MVC中控制器负责处理请求,由它操作数据模型,最后返回视图给用户。

IController接口

所有的控制器类以Controller结尾,必须实现System.Web.Mvc.IController接口,一个最简单的控制器类可以是:

  1. public class BasicController : IController {
  2.  
  3. public void Execute(RequestContext requestContext) {
  4.  
  5. string controller = (string)requestContext.RouteData.Values["controller"];
  6. string action = (string)requestContext.RouteData.Values["action"];
  7.  
  8. if (action.ToLower() == "redirect") {
  9. requestContext.HttpContext.Response.Redirect("/Derived/Index");
  10. } else {
  11. requestContext.HttpContext.Response.Write(
  12. string.Format("Controller: {0}, Action: {1}",
  13. controller, action));
  14. }
  15. }
  16. }

BasicController类实现了IController的唯一方法Execute(),在上面的例子中直接返回数据到请求响应,我们可以根据自己的需求来灵活的处理客户请求。

Controller类

更多的时候我们直接继承MVC已经定义的控制类System.Web.Mvc.Controller:

  1. public class DerivedController : Controller
  2. {
  3.  
  4. public ActionResult Index()
  5. {
  6. ViewBag.Message = "Hello from the DerivedController Index method";
  7. return View("MyView");
  8. }
  9.  
  10. }

Controller类封装的IController.Execute()方法会调用我们定义的Action方法,比如这里的Index()。Controller同时为我们提供了众多的属性来方便获取相关数据:

  • Request:比如Request.QueryString、Request.Url、Request.Form、Request.HttpMethod等。
  • Response:可以直接向Response返回数据到用户。
  • RouteData:和路径映射相关的数据,比如RouteData.Route、RouteData.Values。
  • HttpContext:比如HttpContext.HttpSessionStateBAse、HttpContext.Items。
  • User:当前已会话已认证的用户信息。
  • TempData:存储当前用户的一些临时信息,可以传递给View。

一些获取Controller数据的例子:

  1. string userName = User.Identity.Name;
  2. string serverName = Server.MachineName;
  3. string clientIP = Request.UserHostAddress;
  4. DateTime dateStamp = HttpContext.Timestamp;
  5. AuditRequest(userName, serverName, clientIP, dateStamp, "Renaming product");
  6. // Retrieve posted data from Request.Form
  7. string oldProductName = Request.Form["OldName"];
  8. string newProductName = Request.Form["NewName"];
  9. bool result = AttemptProductRename(oldProductName, newProductName);
  10. ViewData["RenameResult"] = result;
  11. return View("ProductRenamed");

Action方法参数

控制器Action方法可以带一系列的参数,比如:

  1. ...
  2. public ActionResult ShowWeatherForecast(string city, DateTime forDate) {
  3. // ... implement weather forecast here ...
  4. return View();
  5. }
  6. ...

这些参数是由MVC的Value providers和model binders所提供的,MVC自动从请求数据等中自动按名称为我们解析参数值并做类型转换,比如上面例子中的city和forDate可能来自于:

  1. string city = (string)RouteData.Values["city"];
  2. DateTime forDate = DateTime.Parse(Request.Form["forDate"]);

响应输出

我们可以从Icontroller的Excecute()方法中直接输出响应,也可以在Controller中使用Response直接输出响应:

  1. public void ProduceOutput()
  2. {
  3. if (Server.MachineName == "TINY")
  4. {
  5. Response.Redirect("/Basic/Index");
  6. }
  7. else
  8. {
  9. Response.Write("Controller: Derived, Action: ProduceOutput");
  10. }
  11. }

这里的Action方法ProduceOutput没有返回值,更多的时候,我们返回一个ActionResult对象,比如View("MyView")返回一个ViewResult,ViewResult继承自ActionResult。甚至我们可以创建自定义的ActionResult类来使用:

  1. public class CustomRedirectResult : ActionResult {
  2.   public string Url { get; set; }
  3.   public override void ExecuteResult(ControllerContext context) {
  4.   string fullUrl = UrlHelper.GenerateContentUrl(Url, context.HttpContext);
  5.   context.HttpContext.Response.Redirect(fullUrl);
  6.   }
  7. }

在控制器Action方法中返回自定义的ActionResult对象:

  1. public ActionResultProduceOutput() {
  2.   if (Server.MachineName == "TINY") {
  3.       return new CustomRedirectResult { Url = "/Basic/Index" };
  4.     } else {
  5.       Response.Write("Controller: Derived, Action: ProduceOutput");
  6.       return null;
  7.     }
  8. }

这里创建了一个实现重定向的ActionResult对象,实际上MVC已经为我们提供了RedirectResult来实现这个功能:

  1. ...
  2. public ActionResult ProduceOutput() {
  3. return new RedirectResult("/Basic/Index");
  4. }
  5. ...

或者更方便的调用Controller的Redirect()方法:

  1. ...
  2. public ActionResult ProduceOutput() {
  3. return Redirect("/Basic/Index");
  4. }
  5. ...

除了RedirectResult,MVC还提供这些ActionResult:

  • ViewResult:渲染一个视图,等同于控制器中调用View()
  • PartialViewResult:渲染部分视图,等同于控制器中调用PartialView()
  • RedirectToRouteResult:根据指定的路由信息发出一个HTTP 301或者302重定向命令,等同于控制器调用RedirectToAction 、RedirectToActionPermanent 、RedirectToRoute 、RedirectToRoutePermanent。
  • HttpUnauthorizedResult:设置HTTP状态码401表示未授权。
  • HttpNotFoundResult:返回HTTP 404-NOT FOUD错误,等同于控制器调用HttpNotFound()。
  • HttpStatusCodeResult:返回自定义的HTTP状态码
  • EmptyResult:不返回任何信息。

返回视图

用得最多的就是在控制器Action方法中返回一个视图,由它渲染HTML返回给用户。我们可以不带任何参数调用View(),MVC会查找和Action方法同名(不带Controller)的View,也可以直接在参数中指定视图的名称:

  1. public ViewResult Index() {
  2.   return View("Homepage");
  3. }

MVC在应用目录下搜索视图,如果启用了区域Area,搜索路径为:

  1. /Areas/<AreaName>/Views/<ControllerName>/<ViewName>.aspx
  2. /Areas/<AreaName>/Views/<ControllerName>/<ViewName>.ascx
  3. /Areas/<AreaName>/Views/Shared/<ViewName>.aspx
  4. /Areas/<AreaName>/Views/Shared/<ViewName>.ascx
  5. /Areas/<AreaName>/Views/<ControllerName>/<ViewName>.cshtml
  6. /Areas/<AreaName>/Views/<ControllerName>/<ViewName>.vbhtml
  7. /Areas/<AreaName>/Views/Shared/<ViewName>.cshtml
  8. /Areas/<AreaName>/Views/Shared/<ViewName>.vbhtml

如果没有使用Area,搜索路径为:

  1. /Views/<ControllerName>/<ViewName>.aspx
  2. /Views/<ControllerName>/<ViewName>.ascx
  3. /Views/Shared/<ViewName>.aspx
  4. /Views/Shared/<ViewName>.ascx
  5. /Views/<ControllerName>/<ViewName>.cshtml
  6. /Views/<ControllerName>/<ViewName>.vbhtml
  7. /Views/Shared/<ViewName>.cshtml
  8. /Views/Shared/<ViewName>.vbhtml

MVC如果按照上述顺序搜索视图,如果找到一个文件就停止搜索,如果没有可用的视图文件会返回资源未找到错误。注意MVC会搜索ASPX视图引擎的老式文件.aspx和.ascx。

View方法还有其他一些重载调用方式:

  1. return View("Index", "_AlternateLayoutPage"); //指定要使用的布局模板
  2. return View("~/Views/Other/Index.cshtml"); //直接指定要使用的视图模板,必须以/或者~/开头。

从控制器向视图传递数据

我们可以在调用View()直接指定要传递给视图的数据:

  1. ...
  2. public ViewResult Index() {
  3. DateTime date = DateTime.Now;
  4. return View(date);
  5. }
  6. ...

在视图中使用传入的数据:

  1. @{
  2. ViewBag.Title = "Index";
  3. }
  4. <h2>Index</h2>
  5. The day is: @(((DateTime)Model).DayOfWeek)

对于强类型的视图,使用起来更方便:

  1. @model DateTime
  2. @{
  3. ViewBag.Title = "Index";
  4. }
  5. <h2>Index</h2>
  6. The day is: @Model.DayOfWeek

也可以使用ViewBag来传递,它是一个动态的键值对集合:

  1. public ViewResult Index() {
  2. ViewBag.Message = "Hello";
  3. ViewBag.Date = DateTime.Now;
  4. return View();
  5. }

在视图中使用:

  1. @{
  2. ViewBag.Title = "Index";
  3. }
  4. <h2>Index</h2>
  5. The day is: @ViewBag.Date.DayOfWeek
  6. <p />
  7. The message is: @ViewBag.Message

Viewbag比视图模型好在可以传递多个值,但是VS不会给出IntelliSense提示,只会在渲染视图时给出错误信息。

重定向

在上面我们已经看到可以使用Redirect重定向请求:

  1. public RedirectResult Redirect() {
  2. return Redirect("/Example/Index");
  3. }

也可以使用RedirectPermanent永久重定向:

  1. return RedirectPermanent("/Example/Index");

和Redirect临时重定向发出302 HTTP代码不同,RedirectPermanent发回301 HTTP代码,前者指示浏览器重新GET新的URL,而后者指示浏览器缓存重定向信息,以后针对老URL的请求自动转向新URL。

除了重定向到URL,我们可以重定向到路径映射方法:

  1. public RedirectToRouteResult Redirect() {
  2.   return RedirectToRoute(new { controller = "Example", action = "Index", ID = "MyID" });
  3. }

或者一个Action方法:

  1. public RedirectToRouteResult RedirectToRoute() {
  2. return RedirectToAction("Index");
  3. }

可以指定是某个控制器的某个Action方法:

  1. public RedirectToRouteResult Redirect() {
  2. return RedirectToAction("Index", "Basic");
  3. }

如果在重定向另一个控制器的Action时我们想要传递数据该怎么办呢?我们可以使用TempData:

  1. public RedirectToRouteResult RedirectToRoute() {
  2. TempData["Message"] = "Hello";
  3. TempData["Date"] = DateTime.Now;
  4. return RedirectToAction("Index");
  5. }

在新的视图中读取TempData:

  1. @{
  2. ViewBag.Title = "Index";
  3. }
  4. <h2>Index</h2>
  5. The day is: @(((DateTime)TempData["Date"]).DayOfWeek)
  6. <p />
  7. The message is: @TempData["Message"]

和ViewBag只用于控制器和同名视图不同,TempData类似于会话Session数据,可以在不同控制器/视图中共享,但是和Session跨请求不同的是一旦读取了TempData的数据TempData就会被删除。TempData.Peek读取数据但是不删除数据:

  1. DateTime time = (DateTime)TempData.Peek("Date");

TempData.Keep可以标记数据不被删除,但是如果再被读取又会再次标记删除,类似于引用计数器:

  1. TempData.Keep("Date");

返回HTTP状态码

我们可以返回一个HTTP状态码比如404错误:

  1. public HttpStatusCodeResult StatusCode() {
  2. return new HttpStatusCodeResult(, "URL cannot be serviced");
  3. }

或者直接调用:

  1. return HttpNotFound();

401未授权错误:

  1. return new HttpUnauthorizedResult();

以上为对《Apress Pro ASP.NET MVC 4》第四版相关内容的总结,不详之处参见原版 http://www.apress.com/9781430242369

ASP.NET MVC 4 (二)控制器的更多相关文章

  1. ASP.NET MVC 视图(二)

    ASP.NET MVC 视图(二) 前言 上篇中对于视图引擎只是做了简单的演示,对于真正的理解视图引擎的工作过程可能还有点模糊,本篇将会对由MVC框架提供给我们的Razor视图引擎的整个执行过程做一个 ...

  2. ASP.NET MVC学习之控制器篇扩展性

    原文:ASP.NET MVC学习之控制器篇扩展性 一.前言 在之前的一篇随笔中已经讲述过控制器,而今天的随笔是作为之前的扩展. 二.正文 1.自定义动作方法 相信大家在开发过程一定会遇到动作方法的重名 ...

  3. ASP.NET MVC 5 04 - 控制器

    PS: 唉.本来这一篇前几天早就应该发了的,可是谁每月没有那么几天啊... 呵呵.开个玩笑.反正就是各种烦气,所以也就一直没上来继续发了. 年底了,摆正一下心态吧.好好干,整点钱,过年回家能跟亲朋好友 ...

  4. ASP.NET MVC 路由(二)

     ASP.NET MVC路由(二) 前言 在上一篇中,提及了Route.RouteCollection对象的一些信息,以及它们的结构所对应的关系.按照处理流程走下来还有遗留的疑问没有解决这个篇幅就来讲 ...

  5. ASP.NET MVC 5 -从控制器访问数据模型

    在本节中,您将创建一个新的MoviesController类,并在这个Controller类里编写代码来取得电影数据,并使用视图模板将数据展示在浏览器里. 在开始下一步前,先Build一下应用程序(生 ...

  6. asp.net MVC 框架中控制器里使用Newtonsoft.Json对前端传过来的字符串进行解析

    下面我用一个实例来和大家分享一下我的经验,asp.net MVC 框架中控制器里使用Newtonsoft.Json对前端传过来的字符串进行解析. using Newtonsoft.Json; usin ...

  7. 【ASP.NET MVC系列】浅谈ASP.NET MVC 视图与控制器传递数据

    ASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作 ...

  8. [转]ASP.NET MVC 5 -从控制器访问数据模型

    在本节中,您将创建一个新的MoviesController类,并在这个Controller类里编写代码来取得电影数据,并使用视图模板将数据展示在浏览器里. 在开始下一步前,先Build一下应用程序(生 ...

  9. ASP.NET MVC学习之控制器篇(二)

    原文链接:http://www.asp.net/learn/mvc/ 这篇教程探索了ASP.NET MVC控制器(controller).控制器动作(controller action)和动作结果(a ...

随机推荐

  1. 七牛图片存储api

    https://developer.qiniu.com/kodo 属于对象存储 https://www.qiniu.com/prices 如何获取存储文件的外链接 https://developer. ...

  2. PHP 打乱数组

    $arr = array( array( "id"=>1, "name"=>"张三", "sex"=> ...

  3. mysql 删除

    DROP删表,表结构将删了,当然数据也不存在了 TRUNCATE和DELETE删数据,表结构还在 DELETE可以带条件删除,TRUNCATE是全部删除 DELETE删除会写日志,TRUNCATE不写 ...

  4. Selenium常用操作汇总二——如何操作cookies(转)

    Web 测试中我们经常会接触到Cookies,一个Cookies主要属性有”所在域.name.value.有效日期和路径",下面来讲一下怎么操作Cookies. import java.ut ...

  5. C++标准 bind函数用法与C#简单实现

    在看C++标准程序库书中,看到bind1st,bind2nd及bind的用法,当时就有一种熟悉感,仔细想了下,是F#里提到的柯里化.下面是维基百科的解释:在计算机科学中,柯里化(英语:Currying ...

  6. MySQL5.5.21图解教程

    大家都知道MySQL是一款中.小型关系型数据库管理系统,很具有实用性,对于我们学习很多技术都有帮助,前几天我分别装了SQL Server 2008和Oracle 10g数据库,也用了JDBC去连接他们 ...

  7. JS 同一标签随机不停切换数据点菜--解决选择困难症

    可视化的 <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF- ...

  8. 信噪比——信号加噪相关的知识

    信噪比:即Signal noise ratio , 即SNR: 它的单位为 dB, 公式为: SNR = 10lg(PS / PN), 其中 ps 表示信号的有效功率, pn 表示噪声的有效功率: 如 ...

  9. PHP + Smarty + html5 构建Wap应用

    一 简介     Smarty是一个PHP编写的模板引擎(template engine),主要用于构建web应用程序的表示层.Smarty的主页是http://www.smarty.net/down ...

  10. Java如何中断正在运行的线程?

    在Java编程中,如何中断正在运行的线程? 以下示例演示如何使用Thread类的interrupt()方法中断正在运行线程,并检查线程是否使用isInterrupted()方法中断. package ...