ASP.NET MVC 5 04 - 控制器
PS:
唉、本来这一篇前几天早就应该发了的,可是谁每月没有那么几天啊。。。
呵呵。开个玩笑。反正就是各种烦气,所以也就一直没上来继续发了。
年底了,摆正一下心态吧。好好干,整点钱,过年回家能跟亲朋好友好好装装逼啊是不。哈哈。
本篇目录:
1. 控制器的角色
1.1 控制器简史
2. 控制器基础
2.2 创建第一个控制器
2.2.1 创建新控制器
2.2.2 编写操作方法
2.2.3 经验总结
3. 小结
▁▃▅ 控制器 ▅▃▁
本篇将阐述ASP.NET MVC中的控制器是如何响应用户的HTTP请求 并将处理的结果信息返回给浏览器,重点介绍和演示控制器和控制器操作的功能。
由于咱们还没涉及到视图和模型(也就是MVC中的V和M),所以本篇涉及到的视图和模型的内容算是超前的,大家瞅瞅就行了,后面会单独着重介绍。
正好也为后面学习打下一点点基础。
在前面几篇内容中,咱们概括性的介绍了MVC模式,然后对ASP.NET Web Forms和ASP.NET MVC进行了比较。
那么下面,也就是本篇内容,我们将深入学习MVC模式中的三个核心元素之一 —— 控制器。
1. 控制器的角色
讨论一个问题最好的方式是从其定义开始,然后在深入讨论其细节。
在本篇内容中,牢记控制器的定义,这将让你理解控制器的含义及其应用有非常大的帮助。
MVC模式中的控制器(Controller)主要负责响应用户的输入,并且在响应时修改模型(Model)。
通过这种方式,MVC模式中的控制器主要关注的就是应用程序流、输入参数的处理,以及对相关视图(View)输出数据的提供了。
过去的Web服务器支持访问以静态文件存储在磁盘上的HTML页面。随着动态网页的盛行,Web服务器也支持由存储在服务器上的动态脚本生成的HTML页面了。
MVC则略有不同,请求的URL地址首先告知路由机制(后面的内容将会详细介绍)去实例化哪个控制器、调用哪个操作方法、并为该方法提供需要的参数。然后控制器的方法决定使用那个视图,并对该视图进行渲染。
URL并不与存储在Web服务器磁盘上的文件有直接对应关系,而是与控制器类的方法有关。
ASP.NET MVC对MVC模式中的前端控制器进行了改造,正如咱们后面要学习的,路由系统在前面,之后才是控制器。
理解MVC模式在Web场景中工作原理的便捷方法就是记住、多练!
MVC提供的是方法调用的结果,而不是动态生成的页面。
1.1 控制器简史
对历史不感冒的可以跳过了,不过个人建议,哪怕读不懂,哪怕一目十行,瞅一遍总是有好处的。
MVC已经出现了很长一段时间 —— 可以追溯到现代Web应用程序时代来临前的几十年。
当MVC第一次开发出来的时候,图形用户界面(GUI)才刚刚起步,并且在不断演化发展。
当时,当用户按下一个按键或单击屏幕时,某个进程会“监听到”他们的动作,这个进程就是控制器。
控制器主要负责接收和解释输入,并更新任何需要的数据类(模型Model),然后通知用户进行的修改或程序更新界面显示(视图View)。
20世纪70年代末和80年代初,Xerox PARC(刚好也是MVC模式诞生的地方)的研究员考试研究GUI的概念,在GUI中用户“工作”在一个虚拟的“桌面”环境中,在这种环境下,用户可以单击和来回拖拽物件。
从这里产生了事件驱动编程的思想 —— 根据用户触发的事件(如单击或是敲击键盘上的按键)来执行响应的程序操作。
后来,随着GUI成为规范,MVC模式就不完全地适合这些新系统了,这一点变得越来越明显了。
在此类系统中,由GUI组件负责处理用户输入,比如当按下一个按钮时,是该按钮本身响应鼠标单击,而不是控制器。
按钮转而将以此通知所有单击的观察者或侦听者它被单击了。
相对于MVC模式而言,另一些模式,比如模型-视图-表示器(Model-View-Presenter,MVP)则表现的与这些现代系统更贴近。
ASP.NET Web Forms是一个基于事件的系统,这在Web应用程序中是独一无二的。它拥有一个强大的基于控件和事件驱动的编程模型,从而为开发人员进行Web开发提供了一个良好的组件化GUI。
当单击一个按钮时,Button控件将会做出响应,并在服务器端引发一个事件以告知它被单击。
这种方法的秒出在于它可以让开发人员在更高的抽象级别下编写代码。
不过,进行更深入的分析则会发现,靠站的很多工作都是在模拟这种组件化的事件驱动。
然而本质上,当单击一个按钮时,浏览器将向包含了页面上控件状态的服务器提交一个请求,控件所在的页面会被封装在一个编码的隐藏输入中。
在服务器端,为了响应该请求,ASP.NET必须重建整个控件层次结构,然后解释请求,并利用请求的内容来恢复应用程序中用户的当前状态。
究其本质,所有这些都是因为Webb是无状态的。因此,当使用富客户端的Windows GUI应用程序时,没必要每当用户单击一个UI小部件时就重建整个屏幕和控件层级结构,因为应用程序保持了原状态,不曾改变。
对于Web程序而言,用户的应用程序状态实质上是消失的。只不过是后来用户每次单击后都会恢复。
虽然这会极大地简化程序,但是以HTML形式出现的用户界面需要从服务器发送到客户端浏览器。这就引发一个问题:“应用程序在哪里?”。
对于大多数的Web页面而言,应用程序就在客户端和服务器之间交互。每次都维持一个小状态,可能是客户端的一个cookie或是服务器上的一块内存,一切都被小心的设计用来掩盖一个小小的“谎言”,这个“谎言”就是Internet和HTTP之间可以进行有状态的编程。不管怎么掩盖都是明显的扯犊子。
当进行Web开发时,事件驱动编程方法(即“状态”概念)的支撑作用将不复存在,并且许多人不愿接受这个虚拟有状态平台的“谎言”。鉴于此,业界已经见证了MVC模式的复兴(尽管对其做了一点轻微的改动)。
下面给出一个改动的示例。在传统的MVC模式中,模型可以通过与视图的间接联系来“观察”视图,这就允许模型根据视图的事件来进行自我调整。
对于在Web开发中应用MVC模式而言,当视图被发送到客户端浏览器时,模型通常已经不再内存当众,所以不再能观察视图上的事件(后面当我们讨论Ajax的时候,将会看到这个例外)。
在Web开发中采用MVC模式,控制器再次走在了前列。应用MVC模式要求Web应用程序中的每一个用户输入只采用请求的方式。
例如,在ASP.NET MVC中,每个请求都被路由转到控制器的一个方法,该控制器全权负责解释这些请求,如有必要,还要操纵模型数据,然后选择一个视图反馈给用户。
上面扩展了一部分理论知识,接下来深入讲解ASP.NET MVC控制器的具体实现。我们将继续使用前面已经创建好的项目。
如果您跳过了直接看本篇的,回头瞅瞅就行了。
2. 控制器基础
在MVC入门时会遇到像先有鸡还是先有蛋这样的问题,需要理解三个部分(模型、视图和控制器),但在不理解其他部分的情况下,要深入其中一部分是很难的。
因此,再开始学习MVC时,需要首先概括地了解控制器,暂时先不管模型和视图。
讲解了控制器的基本工作原理之后,然后咱们再深入学习视图、模型和其他ASP.NET MVC开发主题。最后的文章中,咱们还会再学习高级控制器。
2.1 简单示例:Home Controller
再开始实质性地编写代码之前,首先了解一下在一个新的项目中默认都包含那些内容。
用Internet Application模板创建的项目包含两个控制器类:
- Home Controller:负责网站根目录下的“home page”、“about page”、“contact page”。
- Account Controller:响应与账户相关的请求,比如登录和账户注册。
在Visual Studio的项目中,展开/Controller文件夹,打开HomeController.cs文件,如图1所示:

图1 - 控制器 HomeController.cs
注意这是一个相当简单的类,它继承了Controller基类。HomeController类的Index方法负责决定当浏览网站首页时触发的事件。
下面按照以下步骤对程序进行简单的修改,然后运行程序。
(1) 用自己想要的短语替换About方法中的“Your application description page.”,比如“Boom、ShaKaLaKa!”。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace BookStore.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult About()
{
ViewBag.Message = "Boom、ShaKaLaKa!";
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
}
}
修改About方法后的HomeController.cs
(2) 按下F5键或者使用“调试 - 启动调试”菜单项运行应用程序,Visual Studio编译应用程序并启动运行在IIS Express下的站点。
IIS Express和ASP.NET开发服务器
Visual Studio 2013包括IIS Express,这是IIS的本地开发版本,可以用来在一个随机的空闲端口上运行网站。
如图2,网站在“http://localhost:5831/”上运行,因此它采用的端口号是5831,你运行时的端口号可能与这个不同。
Visual Studio 2010及其以下版本使用的是Visual Studio Development Swerver(有时也称它的老代号Cassini),而不是IIS Express。
尽管Development Server很像IIS,但IIS Express实际上是IIS的优化版本,优化后使它更适用于开发。
想更多地了解IIS Express,请自行Google。
(3) 接下来,会打开一个浏览器窗口,显示网站的首页,如图2所示:

图2 - 初次启动后的网站首页
(4) 点击导航菜单的“关于”,浏览到/Home/About,打开关于页面,你修改的消息就显示出来了,如图3:

图3 - 显示修改后的信息“Boom、ShaKaLaKa!”
现在已经创建了一个新项目并在屏幕上显示了指定的信息,接下来通过创建一个新的控制器来创建一个实际的应用程序。
2.2 创建第一个控制器
首先创建一个控制器来处理有关浏览图书目录的URL。这个控制器支持一下三个功能:
- 索引页面列出商店里包含的图书类型;
- 单击一个类型,跳转到一个列出该类型下所有图书的页面;
- 单击一个图书,跳转到一个列出有关该图书的所有信息的页面。
2.2.1 创建新控制器
创建控制器,首先需要添加一个新的StoreController类。具体方法如下:
(1) 右击“解决方案资源管理器”下项目里面的“Controller”文件夹,右键“添加 - 控制器”,如图4所示;
(2) 模板类型选择“MVC5 控制器 - 空”,如图5所示;
(3) 强控制器命名为“StoreController”,然后单击添加按钮,如图6所示。

图4 - 右键项目Controller文件夹 - 新建控制器

图5 - 选择控制器类型

图6 - 输入控制器名称
2.2.2 编写操作方法
新创建的StoreController控制器已经有了一个Index()方法,下面将利用这个Index()方法实现在页面上列出图书商店里面所有图书类别的功能。
另外,还需要添加两个额外的方法来实现上面说到的其他两项功能,分别是Category()和Details()。
控制器中的这些方法(Index()、Category()、Details())成为控制器操作。
正如上述的HomeController.Index()操作方法那样,控制器操作的是响应URL请求,执行相应的操作,并向浏览器或是单击这个URL的用户做出响应。
要了解控制器操作的工作原理,可按照以下的步骤操作:
(1) 将Index()方法的返回数据类型改为 string (而不是 ActionResult );
然后将返回值 return View(); 改为 return "请求来自:Store.Index() !"; 。
修改后的StoreController.cs如下所示:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace BookStore.Controllers
{
public class StoreController : Controller
{
public string Index()
{
return "请求来自:Store.Index() !";
}
}
}
(2) 添加对商店的Category()方法,将返回设置为 return "请求来自:Store.Category() !"; ;
添加浏览详细信息的Details()方法,将返回设置为 return "请求来自:Store.Details() !"; 。
控制器StoreController的完整代码如下所示:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace BookStore.Controllers
{
public class StoreController : Controller
{
public string Index()
{
return "请求来自:Store.Index() !";
}
public string Category()
{
return "请求来自:Store.Category() !";
}
public string Details()
{
return "请求来自:Store.Details() !";
}
}
}
(3) 重新运行项目,然后浏览一下URL:
- /Store
- /Store/Category
- /Store/Details
访问这些URL会调用控制器中的操作方法,然后返回相应字符串,如图7、8、9所示:

图7 - 浏览/Store

图8 - 浏览/Store/Category

图9 - 浏览/Store/Details
2.2.3 经验总结
从以上这个姜丹实验中可以得出以下几个结论:
- 不需要做任何额外的配置,浏览到/Store/Details就可以执行StoreController类中的Details()操作方法,这就是操作中的路由为我们提供的。
稍后还会简单介绍路由,详细的介绍我们后面单独再谈。 - 尽管是使用Visual Studio工具来创建这个控制器类,但它的确是一个非常简单的类。
判别一个类是否是控制器类的唯一方式,就是查看该类是否继承自System.Web.Mvc.Controller。 - 已经利用一个控制器在浏览器中显示了文本 —— 没有用到模型和视图。
尽管在ASP.NET MVC中模型和视图非常有用,但控制器才是真正的核心。每一个请求都必须通过控制器处理,然而其中有些请求是不需要模型和视图的。
2.3 控制器操作中的参数
前面的例子返回输出的是常量字符串。 下一步就是让它们通过响应URL传进来的参数动态地执行操作。按以下步骤来实现:
(1) 把Category()操作方法修改为,查找URL传过来的查询字符串值。
可以通过在操作方法中添加一个string类型的“categoryName”参数来实现这个功能。
然后,当这个方法被调用时,ASP.NET MVC会自动将名为“categoryName”的查询字符串或表单提交参数传递给Category()操作方法。
public string Category(string categoryName)
{
string message = HttpUtility.HtmlEncode("Store.Category(),CategoryName=" + categoryName);
return message;
}
HTML编码的用户输入
利用方法HttpUtility.HtmlEncode()来预处理用户输入。这样就能阻止用户用链接向视图中注入Javascript代码或HTML标记,也就可以防止XSS注入了。
例如用户访问: /Store/Category?categoryName=<script>window.location='http://www.geeksss.com'</script> ,甚至插入其他恶意Javascript等等。
(2) 上面的操作完事儿了之后,我们浏览 /Store/Category?categoryName=Java ,结果如图10所示:

图10 - 浏览Category()操作方法,并传递参数categoryName=Java
这表明控制器操作可以将查询字符串作为其操作方法的参数来接收。
(3) 修改Details()操作方法,使其读取和显示一个名为ID的输入参数。
这里不像前面的方法那样把ID值作为一个查询字符串参数,而是将ID直接嵌入到URL中,如: /Store/Details/ 。
ASP.NET MVC再不需要任何额外配置的情况下可以很容易地做到这一点。
ASP.NET MVC的默认路由约定,就是将操作方法名称后面URL的这个片段( 例如上面的 /Store/Details/ 中的520)作为一个参数,该参数的名称为ID。
如果操作方法中又名为ID的参数,那么ASP.NET MVC会自动将这个URL片段作为ID参数传递过来。
public string Details(int id)
{
string message = "Store.Details(),ID=" + id;
return message;
}
(4) 运行应用程序,浏览到/Store/Details/520,如图11所示:

图11 - 为Details()操作方法添加id参数并访问
像前面示例演示的那样,控制器操作感觉就像是Web浏览器直接调用控制器类中对应的操作方法。
类、操作方法和参数都被具体化为URL中的特定路径片段或查询字符串,结果就是一个返回给浏览器的字符串。
这就是进行了极大的简化,而忽略了下面这些的细节:
- 路由将URL映射到操作方法的具体方式;
- 将试图作为模板生成返回给浏览器的字符串(通常是HTML格式);
- 操作很少返回原始的字符串,它通常返回合适的ActionResult类处理像HTTP状态码和调用视图模板系统这样的事项。
控制器提供了很多自定义和扩展的功能,但是我们很少能用到这些内容。
在一般应用程序中,控制器通过URL被调用,然后执行自定义的代码并返回一个视图。先记住这些内容,后面我们会详细介绍关于控制器如何定义、调用和扩展的底层细节。
3. 小结
现在已经学习了足够的控制器知识,下面就可以与视图结合起来使用了,下一篇我们将对此进行详细的介绍。
ASP.NET MVC 5 04 - 控制器的更多相关文章
- 【ASP.NET MVC系列】浅谈ASP.NET MVC 视图与控制器传递数据
ASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作 ...
- ASP.NET MVC 5 -从控制器访问数据模型
在本节中,您将创建一个新的MoviesController类,并在这个Controller类里编写代码来取得电影数据,并使用视图模板将数据展示在浏览器里. 在开始下一步前,先Build一下应用程序(生 ...
- ASP.NET MVC学习之控制器篇扩展性
原文:ASP.NET MVC学习之控制器篇扩展性 一.前言 在之前的一篇随笔中已经讲述过控制器,而今天的随笔是作为之前的扩展. 二.正文 1.自定义动作方法 相信大家在开发过程一定会遇到动作方法的重名 ...
- asp.net MVC 框架中控制器里使用Newtonsoft.Json对前端传过来的字符串进行解析
下面我用一个实例来和大家分享一下我的经验,asp.net MVC 框架中控制器里使用Newtonsoft.Json对前端传过来的字符串进行解析. using Newtonsoft.Json; usin ...
- [转]ASP.NET MVC 5 -从控制器访问数据模型
在本节中,您将创建一个新的MoviesController类,并在这个Controller类里编写代码来取得电影数据,并使用视图模板将数据展示在浏览器里. 在开始下一步前,先Build一下应用程序(生 ...
- ASP.NET MVC之从控制器传递数据到视图四种方式(一)
前言 本系列开始着手讲述ASP.NET MVC,也算是自己对基础的回顾以及进一步深入学习,保证每天发表一篇该系列文章,关于基本知识则不再叙述,园子有关文章不胜枚举,这一系列若有叙述不当或错误之处,欢迎 ...
- ASP.NET MVC系列:添加控制器
基于MVC的应用程序包含三个部分 Models(模型):对应用程序的数据进行处理 Views(视图):动态生成HTML,显示数据 Controllers(控制器):应用程序中处理用户交互的部分,处理浏 ...
- ASP.NET MVC学习之控制器篇
一.前言 许久之后终于可以继续我的ASP.NET MVC连载了,之前我们全面的讲述了路由相关的知识,下面我们将开始控制器和动作的讲解. ASP.NET MVC学习之路由篇幅(1) ASP.NET MV ...
- ASP.NET MVC学习之控制器篇(二)
原文链接:http://www.asp.net/learn/mvc/ 这篇教程探索了ASP.NET MVC控制器(controller).控制器动作(controller action)和动作结果(a ...
随机推荐
- Windows Server 2012 磁盘管理之 简单卷、跨区卷、带区卷、镜像卷和RAID-5卷
今天给客户配置故障转移群集,在Windows Server 2012 R2的系统上,通过iSCSI连接上DELL的SAN存储后,在磁盘管理里面发现可以新建 简单卷.跨区卷.带区卷.镜像卷.RAID-5 ...
- EasyPR--开发详解(7)字符分割
大家好,好久不见了. 一转眼距离上一篇博客已经是4个月前的事了.要问博主这段时间去干了什么,我只能说:我去“外面看了看”. 图1 我想去看看 在外面跟几家创业公司谈了谈,交流了一些大数据与机器视觉相关 ...
- Chrome 控制台不完全指南
Chrome的开发者工具已经强大到没朋友的地步了,特别是其功能丰富界面友好的console,使用得当可以有如下功效: 更高「逼格」更快「开发调试」更强「进阶级的Frontender」 Bug无处遁形「 ...
- C++11网络编程
Handy是一个简洁优雅的C++11网络库,适用于linux与Mac平台.十行代码即可完成一个完整的网络服务器. 下面是echo服务器的代码: #include <handy/handy.h&g ...
- 从零开始编写自己的C#框架(18)——Web层后端权限模块——菜单管理
从本章开始,主要讲解的是页面中对框架相关功能的调用方法,比如列表页面(又分为有层次感列表和普通列表).编辑页面.多标签页面等,只要熟悉了这些函数的使用方法,那么开发起来就会很便捷了. 1.如图先创建菜 ...
- Javascript的二进制数据处理学习 ——nodejs环境和浏览器环境分别分析
以前用JavaScript主要是处理常规的数字.字符串.数组对象等数据,基本没有试过用JavaScript处理二进制数据块,最近的项目中涉及到这方面的东西,就花一段时间学了下这方面的API,在此总结一 ...
- C#的Process类调用第三方插件实现PDF文件转SWF文件
在项目开发过程中,有时会需要用到调用第三方程序实现本系统的某一些功能,例如本文中需要使用到的swftools插件,那么如何在程序中使用这个插件,并且该插件是如何将PDF文件转化为SWF文件的呢?接下来 ...
- [JavaEE笔记]Cookie
引言 由于 Http 是一种无状态的协议,服务器单从网络连接上无从知道客户身份. 会话跟踪是 Web 程序中常用的技术,用来跟踪用户的整个会话.常用会话跟踪技术是 Cookie 与 Session. ...
- [AngularJS] AngularJS系列(3) 中级篇之表单验证
目录 基本验证 验证插件messages 自定义验证 基本验证 <form name="form" novalidate ng-app> <span>{{f ...
- 翻译:使用 ASP.NET MVC 4, EF, Knockoutjs and Bootstrap 设计和开发站点 - 1
原文地址:http://ddmvc4.codeplex.com/ 原文名称:Design and Develop a website using ASP.NET MVC 4, EF, Knockout ...