MVC笔记 Controller相关技术

一、Controller的责任

MVC的核心就是Controller(控制器),它负责处理浏览器传送过来的所有请求,并决定要将什么内容响应给浏览器。但Controller并不负责决定内容应该如何显示,而是将特定形态的内容响应给MVC架构,最后才由MVC架构依据响应的形态来决定如何将内容响应给浏览器。如何决定响应内容是View的责任。

二、Controller的类与方法

Controller本身就是一个类(Class),该类有许多方法(Method)。在这些方法中,只要是公开方法,该方法就会被视为是一种动作(Action);只要有动作存在,就可以通过该动作方法接收网页请求并决定响应视图。

由上可知编写Controller的基本要求:

  • Controller必须为公开类。
  • Controller的名称必须以"Controller"结尾。
  • 必须继承自MVC内置的Controller类,或继承自实现IController接口的自定义类,或自行实现IController接口。
  • 所有方法必须为公开方法。改方法可以没有参数,也可以有多个参数。

三、Controller的执行过程

Controller被MvcHandler选中之后,下一步就是通过ActionInvoker选取适当的Action来执行。在Controller中,每一个Action可以定义0到多个参数。ActionInvoke会依据当前的RouteValue及客户端传过来的信息准备好可输入Action参数的依据,最后正式调用被Controller选中的那个Action方法。

Action执行完后的返回值通常是ActionResult类的。事实上,ActionResult类是一个抽象类,因此,MVC本身就实现了许多不同ActionResult类的子类。Controller得到ActionResult类之后,就会开始执行ActionResult类的ExecuteResult()方法,并将执行的结果返回客户端。这时,Controller的任务就算完成了。

Controller在执行时还有一个动作过滤器(Action Filter)机制,可以分成以下4中类型。

  • 授权过滤器(Authorization Filter);
  • 动作过滤器(Action Filter);
  • 结果过滤器(Result Filter);
  • 例外过滤器(Exception Filter)。

此外,在Controller的执行过程中还必须考虑动作过滤器的执行顺序。除上述说明之外,在执行Action与ActionResult类时嗨会有一些事件被执行,这部分将在九中说明。

四、动作名称选取器

通过ActionInvoker选取Controller中的公开方法时,默认会用Reflection(映像)的方式取得Controller中具有相同名字的方法(不区分大小写)。如下程序范例表示得很清楚:当RouteValue表达式中的Action是"Index",默认会执行Index()方法。

 1   public class HomeController : Controller
 2     {
 3         /// <summary>
 4         /// 要求网址 http://localhost/Home/Index
 5         /// </summary>
 6         public ActionResult Index()
 7         {
 8             return View();
 9         }
10
11     }

如果在以上的Action中加入ActionName属性,并将其指名为"Default",此时,若RouteValue表达式中的Action是"Index",就不会执行Index()方法,而必须使RouteValue表达式中的Action为"Default",Index()方法才能被正确执行,这就是动作名称选取器(Action Name Selector)的作用,示例如下。

 1   public class HomeController : Controller
 2     {
 3         /// <summary>
 4         /// 要求网址 http://localhost/Home/Index
 5         /// </summary>
 6         [ActionName("Default")]
 7         public ActionResult Index()
 8         {
 9             return View();
10         }
11
12     }

唯一需要特别注意的是,如果你使用默认的"return View()"方法返回ActionResult类,由于应用了[ActionName("Default")]属性,所以MVC会去寻找"/Views/Home/Default.aspx"页面而不是"/Views/Home/Index.aspx"页面来执行。

五、动作方法选取器

5.1  NonAction属性

若将NonAction属性应用在Controller中的Action方法上,即便该Action方法是公开方法,也会告知ActionInvoke不要选取这个Action来执行。这个属性主要用来保护Controller中的特定公开方法不会被发布到Web上。或是当功能尚未开发完成就要进行部署时,若暂时不想将此方法删除,也可应用这个属性,表示"不要对外公开"。

1        [NonAction]
2         public ActionResult Index()
3         {
4             return View();
5         }

将Action方法中的"public"修改成"privare",也可以达到同样的目的,示例如下:

1        private ActionResult Index()
2         {
3             return View();
4         }

5.2  HttpGet属性、HttpPost属性、HttpDelete属性和HttpPut属性

HttpGet、HttpPost、HttpDelete和HttpPut属性是动作方法选取器的一部分,我们以下列程序为例进行介绍。若应用了[httpPost]属性,表示只有当客户端浏览器发送HTTP POST请求时才可以选取这个Action。

1       [HttpPost]
2         private ActionResult Index()
3         {
4             return View();
5         }

相反的,若果没有应用这些属性,客户端浏览器发送任何HTTP动词,都会自动选取对应的Action。

这些属性常用在需要接受窗口数据的时候。你可以创建两个同名的Action,一个应用[HttpGet]属性来显示窗口HTML,另一个应用[HttpPost]属性来接收窗口送出的值,范例程序如下。

 1         [HttpGet]
 2         public ActionResult Create()
 3         {
 4             return View();
 5         }
 6         [HttpPost]
 7         private ActionResult Create(FormCollection c)
 8         {
 9             UpdateToDB(c);
10             return RedirectToAction("Index");
11         }

 NOTE   由于HTML窗口无法送出"Delete"这个Http动词,所以如果希望Action能提供像RESET协议那样的方式来处理删除动作,又能通过同一个窗口使用这个只允许"Delete"的动作的话,可以用Html.HttpMethodOverride()方法的HTML辅助方法来模拟Http Delete方法的行为,但实际上窗口还是以Http Post的方式送出去的。

六、 ActionResult类

ActionResult类是Action执行的结果,但ActionResult中并不包含执行结果,而是包含执行响应时所需的信息。当Action返回ActionResult类之后,会由MVC执行。先看看ActionResult抽象类的程序代码。在ActionResult抽象类中仅定义了一个ExecuteResult()方法来执行结果。

 1  namespace System.Web.Mvc
 2   {
 3     // 摘要:
 4     //     封装一个操作方法的结果并用于代表该操作方法执行框架级操作。
 5     public abstract class ActionResult
 6     {
 7         // 摘要:
 8         //     初始化 System.Web.Mvc.ActionResult 类的新实例。
 9         protected ActionResult();
10
11         // 摘要:
12         //     通过从 System.Web.Mvc.ActionResult 类继承的自定义类型,启用对操作方法结果的处理。
13         //
14         // 参数:
15         //   context:
16         //     用于执行结果的上下文。上下文信息包括控制器、HTTP 内容、请求上下文和路由数据。
17         public abstract void ExecuteResult(ControllerContext context);
18     }
19   }

MVC定义的ActionResult如表所示:



Contro辅助方法


用 途


ContentResult


Content


返回一段用户自定义的文字内容


EmptyResult


不返回任何数据,即不响应任何数据


JsonResult


Json


将数据序列化成JSON格式返回


RedirectResult


Redirect


重定向到指向的URL


RedirectToRouteResult


RedirectToAction、RedirectToRoute


与RedirectResult类似,但它将新定向到一个Action或Route


ViewResult


View


使用IViewInstance接口和IViewEngine接口,实际输出数据的是IViewEngine接口和View


PartialViewResult


PartialView


与ViewResult类相似,返回的是”部分显示”,即”UserControls”目录下的View


FileResult


File


以二进制串流的方式返回一个文件数据


JavaScriptResult


JavaScript


返回的是JavaScript指令码

表中的Controller辅助方法在Controller类中为返回ActionResult类提供支持,如下程序可用于跳转到另一个页面。

1      [HttpPost]
2         public ActionResult Post(FormCollection c)
3         {
4             return new RedirectResult("/");
5         }

如果使用Controller辅助方法,就可以将以上程序改写如下:

1      [HttpPost]
2         public ActionResult Post(FormCollection c)
3         {
4             return Redirect("/");
5         }

以上两段程序代码其实差不多,但实际操作中则是以使用Controller辅助方法居多。

6.1  ViewResult类

ViewResult类是在MVC中最常用的ActionResult类,用于返回一个标准的视图。通过Controller辅助方法,我们能更方便地定义如何输出视图。指定要输出的View名称、指定该View要应用哪个MasterPage、指定要输入的View的Model。

6.2  PartialViewResult类

PartialViewResult类与ViewResult类非常相似,但它无法为View赋值MasterPage,通常用在前端为Ajax应用程序的情况下,并可以通过Ajax来取得网页中的部分内容。

如下程序会执行"/Views/Home/About.ascx"页面,并将结果输出至客户端。

1        public ActionResult About()
2         {
3             return PartialView();
4         }

6.3  EmptyResult类

有些Action在执行后其实不需要返回任何数据,例如一个页面执行完后直接转到其他页面的情况。EmptyResult类不会执行任何响应客户端的程序,所以也不会返回任何数据,使用方法如下:

1       public ActionResult Empty()
2         {
3             return new EmptyResult();
4         }

在MVC中,还有一种表达EmptyResult类的方式,即将上述语法写成如下:

1        public void Empty()
2         {
3             return;
4         }

有一种情况是用EmptyResult类搭配Response.Redirect()方法进行HTTP 302暂时转向,示例如下:

1       public void Redirect()
2         {
3             Response.Redirect("/Home/Index");
4         }

如果已经开始使用.NET 4.0,也可以考虑使用4.0新增的Respo.RedirectPermanent()方法建立HTTP 301永久转向,示例如下。

1       public void Redirect()
2         {
3             Response.RedirectPermanent("/Home/Index");
4         }

6.4  ContentResult类

ContentResult类可以响应文字内容的结果。可以让ContentResult类响应任意指定文字内容。Content-Type和文字编码(Encoding)。

如下范例将会响应一段XML文字,并设定响应的Content-Type为text/xml(已指定响应的文字编码方式为Encoding.UTF8)。

1       public ActionResult Content()
2         {
3             return Content("<ROOT><TEXT>123</TEXT></ROOT>","text/xml",Encoding.UTF8);
4         }

如果只响应一串HTML字符串,可以只使用第一个参数,如下:

1       public ActionResult Content()
2         {
3             string strHTML = "........";   //省略 HTML的内容
4             return Content(strHTML);
5         }

还有一种方法可以表达如上一样简单的返回类,直接将返回类设定成"string"即可。MVC会进行判断,只要Action返回的不是ActionResult类,就会将返回的类转换成字符串类输出。

6.5  FileResult类

FileResult类可以响应任意的文件内容,包括二进制格式的数据,例如图像文件。PDF文档或ZIP文件,可以输入byte数组、文件路径、stream数据、Content-Type、下载文件名等参数并将其返回客户端。事实上,FileResult是一个抽象类,在MVC中实现FIleResult类的子类共有3个,分别是:

  • FilePathResult:响应一个实体文件;
  • FileContentResult:响应一个byte数组的内容;
  • FileStreamResult:响应一个Stream数据。

但通过Controller类中所提供的File辅助方法可以让你不用记忆这么多。File()辅助方法能自动选取不同的FileResult类进行响应。

如果通过Action输出一个存储在"App_Data"目录栏下的PNG图像文件,可以参考以下代码:

1        public ActionResult GetFile()
2         {
3             return File(Server.MapPath("~/App_Data/UserA/a.png"),"image/png");
4         }

若希望直接通过浏览器下载文件,而不是在浏览器打开文件,可以再第3个参数中输入要求下载的文件名。如:PDF文件来自于数据库,并希望让用户下载,可以先取得一个byte数组或Stream数据,并在File()辅助方法的第2个参数中指定正确的Content-Type,最后再指定要下载的文件名即可。

1       public ActionResult GetFile()
2         {
3             byte[] fileContent = GetFileByteArrayFromDB();
4
5             return File(fileContent,"application/pdf","Report.pdf");
6         }

6.6  强制下载文件时需注意中文文件名的问题

由于MVC支持中文文件名文件下载的能力有限,若要开发出跨浏览器下载中文文件名文件的解决方案,就不能只靠FileResult类了,可以自定义ActionResult类来克服这个问题,也可直接用较为底层的方法来解决。一下将说明强制下载文件的原理及解决方法。

强制下载文件功能时,通常是通过设定"Content-Disposition"这个HTTP响应标头(Response Header)的方式将强制下载文件的要求告知客户端,示例如下。

1        string fileName = "ExportData.csv";
2        string strContentDisposition = String.Format("{0};filename=\"{1}\"", "attachment", fileName);
3        Response.AddHeader("Content-Disposition", strContentDisposition);

通过上述程序代码,就可以让客户端强制下载此页面的内容,也就是说,改页面的内容(可能是文件或二进制文件)不会直接在浏览器中打开,下载后也不会打开相关程序。

Content-Disposition标头的第一组参数是"attachment",代表此文件是一个附件文件,也就是"要求下载"的意思。如果将"attachment"改成".inline"的话,就代表这是一个内嵌于其他网页的文件(如图像文件、CSS、JavaScript、Flash等),而这也是默认的设定,等同于不添加Content-Disposition标头的情况。

6.7  JavaScriptResult类

JavaScriptResult类的用途是将javaScript程序代码响应给浏览器。通过Ajax环境,可以利用JavaScriptResult类来响应适当的JavaScript程序代码并将其交给浏览器动态执行,由于Ajax功能属于View.

6.8  JsonResult类

JSON是Web在实现Ajax应用程序时经常使用的一种数据传输格式,JsonResult类可自动将任意对象的数据序列转换成JSON格式返回。JsonResult类默认的Content-Type为application/json,对于某些JavaScript Framework来说,这是必要的需求,如jQuery。 建议尽量避免使用HTTP GET方法获取JSON数据。但若只使用HTTP POST方法获取JSON数据也存在一个问题,那就是数据无法被浏览器缓存。如果数据敏感度不高且想实现缓存的话,还需让JsonResult类能够对HTTP GET请求进行响应,解决方案就是为JSON()辅助方法加上一个JsonResultBehavior列举参数,这样就可以通过GET方法取得JSON数据了。

1       public ActionResult JSON()
2         {
3             return Json(new
4             {
5                 id = 1,
6                 name = "will",
7                 CreatedOn = DateTime.Now
8             }, JsonRequestBehavior.AllowGet);
9         }

6.9  RedirectResult类

RedirectResult类主要用途是执行指向其他页面的重定向。在RedirectResult类的内部,基本上还是用Response.Redirect()方法响应HTTP 302暂时定向的。

1        public ActionResult Redirect()
2         {
3             return Redirect("/Home/Index");
4         }

6.10 RedirectToRoute类

Controller类中有两个与RedirectToRoute类有关的辅助方法,分别是RedirectToAction()和RedirectToRoute().

1. RedirectToAction()辅助方法

RedirectToAction()方法比较简答,既可通过直接输入Action名称来设定让浏览器转向该Action网址,也可以输入新建的RouteValue值,如下:

  • 转到同一个Controller中的另一个Action。
1       public ActionResult RedirectToActionSample()
2         {
3             return RedirectToAction("SamplePage");
4         }
  • 转到指定Controller的特定Action。
1       public ActionResult RedirectToActionSample()
2         {
3             return RedirectToAction("List", "Member");
4         }
  • 转到MemberController的List Action,并且加上"page"这个RouteValue值。
1       public ActionResult RedirectToActionSample()
2         {
3             return RedirectToAction("List", "Member", new { page = 3 });
4         }

2. RedirectToRoute()辅助方法

RedirectToRoute()辅助方法较为复杂,可利用Global.asax文件中定义的网址路由表来指定不同的转向网址。

  • 转到同一个Controller中的另一个Action。
1       public ActionResult RedirectToRouteSample()
2         {
3             return RedirectToRoute(new { action = "SamplePage" });
4         }
  • 转到指定Controller的特定Action。
1       public ActionResult RedirectToRouteSample()
2         {
3             return RedirectToRoute(new { controller = "Member", action = "list" });
4         }
  • 转到MemberController的List Action,并且加上"page"这个RouteValue。
1       public ActionResult RedirectToRouteSample()
2         {
3             return RedirectToRoute(new { controller = "Member", action = "list", page = 3 });
4         }

七、ViewData与TempData概述

7.1  ViewData

ViewData属性是一个ViewDataDictionary类,可用于存储任意对象的数据,但存储的键值必须为字符串。

ViewData有一个特性,就是它只会存在于当前的HTTP请求中,而不像Session一样可以讲数据带到下一个HTTP请求。

7.2  TempData

TempData的数据结构与ViewData一样,都属于字典类,不过TempData属性的类是TempDataDictionary。TempData嗨有一点不一样的地方,就是它的内部是用Session来存储数据的。存储在TempData中的数据只会暂存:1次网页请求!

1次网页请求的定义:当窗口数据被传送到以下Action中进行存储时,如果发生新建数据失败的情况,我们会希望这次传送的数据可以保留至下一个页面,此时,就会将这个只希望出现1此的信息保存到TempData中,并在下一个页面中执行。

 1        [HttpPost]
 2         public ActionResult Create(Message msg)
 3         {
 4             if (!UpdateMessageToDB(msg))
 5             {
 6                 TempData["PostedMessage"] = msg;
 7                 return RedirectToAction("Create");
 8             }
 9             return RedirectToAction("Index");
10         }

当新建数据失败的情况发生后,将会返回"Create"这个Action,并将原来的数据从TempData中读出,示例如下:

1         [HttpGet]
2         public ActionResult Create()
3         {
4             string data = TempData["PostedMessage"] as Message;
5             return View(data);
6         }

此时,数据就会回到Create()方法,并在此被传送到Create视图。在这个Controller生命周期结束的前一刻,由于MVC会记录"TempData["PostedMessage"]"语句已经被读取了,因此,在网页请求结束之前会将"TempData["PostedMessage"]"语句删除。

八、模型绑定

8.1  简单模型绑定

8.2  使用FormCollection类获取窗口数据

除了可以通过简单模型绑定机制获取窗口传过来的单栏数据之外,我们也可以通过FormCollection类一次获取整个窗口传送过来的数据。只要设定一个FormCollection类的参数,就可以获取所有从窗口传送过来的数据。这种用法与使用Request.Form()方法一样,不过在MVC里还是建议尽量不要用Request.Form()方法来获取窗口数据。

1       public ActionResult GetFormCollection(FormCollection form)
2         {
3             ViewData["uName"] = form["uName"];
4             return View("ModelBinderDemo");
5         }

8.3  复杂模型绑定

8.4  多个复杂模型的绑定

好比一个HTML代码中只有一个Form(表单)窗口,但是该窗口内有两组字段,是因为在编写数据绑定类里面设定了两组参数,分别为form1和form2,而这两组参数的类都是GuestbookForm,如:

1       public Action ComplexModelBinding(GuestbookForm form1, GuestbookForm form2)
2         {
3             InsertIntoDB(form1);
4             InsertIntoDB(form2);
5             return Redi("/");
6         }

只需要做好模型绑定即可。

8.5  判断模型绑定的结果

验证数据,用自身的方法如Html.ValidationMessageFor()方法用来显示特定字段的错误信息。也可在Controller中判断业务逻辑。

九、动作过滤器(略)

时间: 2024-10-18 01:10:49

MVC笔记 Controller相关技术的相关文章

【转载】MVC Area 区域相关技术

创建Area 右键工程选择 添加->区域,弹出如下填写Area的对话框: 点击添加后,工程目录结构如下: 和创建一个空MVC工程结构类似,Admin Area 有自己的 Controllers.Models 和 Views 文件夹,不一样的地方就是多了一个 AdminAreaRegistration.cs 文件,这个文件中定义了一个叫 AdminAreaRegistration 的类,它的内容如下: namespace MvcApplication1.Areas.Admin { public c

[MVC]Area区域相关技术

MVC提供Area机制,在同一个项目之内就能够切割出不同的ASP.NET MVC网站. 插入:首先在相同的位置,比如说同一个文件夹(如:Controllers)是不能创建俩个相同名称的文件(如:HomeController),其次在不同的文件夹中如fold1和fold2,中各自创建一个TestController,程序能够通过编译,但当浏览器视图执行/Test时,网站报出异常,如图: 因为在默认情况下,路由会同时匹配两个controller,造成无法访问. 在项目上,右键,创建区域,问题解决.

MVC之Area相关技术

当在做MVC大型网站时,我们通常会切割成多个模块.但又由于在MVC中如果有Controller名字相同的话,会出错,那如何来解决这个问题呢?微软太人性化了,看下文. 1.新增区域 1)添加区域 2)设置区域名称 3)最后显示 2.默认路由与区域路由的优先级. 我们在打开Global.asax,如下所示 <span style="font-size:18px;"> public class MvcApplication : System.Web.HttpApplication

ASP.NET MVC中Model相关技术

在Model里的程序,由于“只能”跟数据与商业逻辑有关,因此Model专注于如何有效地提供数据访问机制.交易环境.数据格式.商业逻辑验证等工作. 一.使用Code First创建数据模型 数据库开发模式有数据库优先开发模式(Database First Development).模型优先开发模式(Model First Development)和程序代码优先开发模式(Code First Development)这三种.ASP.NET MVC的Model数据库开发模式为程序代码优先开发模式,使用

【转】ASP.NET MVC学习笔记-Controller的ActionResult

1. 返回ViewResult public ActionResult Index()   {       ViewData["Message"] = "Welcome to asp.net MVC!";       return View();   }  public ActionResult Index(){    ViewData["Message"] = "Welcome to ASP.NET MVC!";    re

JEE相关技术浅析

1.1  JEE相关技术浅析 JEE是基于java的web相关技术的统称,包括html.javascript.css.jsp.servlet.struts.spring.hibernate.java.ejb等.为了实现程序的灵活性,采用MVC(Model.View.Controller)的设计模式,将应用分为展现层.业务逻辑层.模型层三个方面. (1)展现层:html.javascript.css属于展现层.html属于纯展示部分,所有操作最终需要合并成html并通过web浏览器展示出来:css

Spring MVC的Controller统一异常处理:HandlerExceptionResolver

出现异常并不可怕,可怕的是出现了异常,你却不知道,也没有进行异常处理. Spring MVC的Controller出现异常的默认处理是响应一个500状态码,再把错误信息显示在页面上,如果用户看到这样的页面,一定会觉得你这个网站太LOW了. 要解决Controller的异常问题,当然也不能在每个处理请求的方法中加上异常处理,那样太繁琐.Spring MVC提供了一个HandlerExceptionResolver接口,可用于统一异常处理. HandlerExceptionResolver接口 pu

[笔记]工作相关

1.最近编写了几个工厂需要的test pattern,用于UHD120和UHD60的pannel上,其中UHD120需要做半分屏处理,存储一行. 2.最近写了UHD120/60/30缩放到FHD120/60/30的算法,采用的算法是双线性算法,相邻4点取平均得到的.需要进行行的存储.注意DPRAM的使用技巧,读写控制逻辑的实现. 3.FHD120/60/30经过FRC处理后 VbyOne的实现是个技术难点. [笔记]工作相关,布布扣,bubuko.com

《淘宝技术这十年》读书笔记 (三). 创造技术TFS和Tair

前面两篇文章介绍了淘宝的发展历程和Java时代的变迁: <淘宝技术这十年>读书笔记 (一).淘宝网技术简介及来源 <淘宝技术这十年>读书笔记 (二).Java时代的脱胎换骨和坚若磐石 马云说过"创新不是为了与对手竞争,而是跟明天竞争",所以这篇文章讲述淘宝的创新技术TFS和Tair及创新的产品. 该篇文章不仅仅对在读大学生非常有所帮助,因为你能从文章中看到很多你需要学习的知识,不仅仅包括数据库.计算机网络.操作系统.数据结构等基础课程:还根据时代的技术变迁讲述了