标签:
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模式中的三个核心元素之一 —— 控制器。
讨论一个问题最好的方式是从其定义开始,然后在深入讨论其细节。
在本篇内容中,牢记控制器的定义,这将让你理解控制器的含义及其应用有非常大的帮助。
MVC模式中的控制器(Controller)主要负责响应用户的输入,并且在响应时修改模型(Model)。
通过这种方式,MVC模式中的控制器主要关注的就是应用程序流、输入参数的处理,以及对相关视图(View)输出数据的提供了。
过去的Web服务器支持访问以静态文件存储在磁盘上的HTML页面。随着动态网页的盛行,Web服务器也支持由存储在服务器上的动态脚本生成的HTML页面了。
MVC则略有不同,请求的URL地址首先告知路由机制(后面的内容将会详细介绍)去实例化哪个控制器、调用哪个操作方法、并为该方法提供需要的参数。然后控制器的方法决定使用那个视图,并对该视图进行渲染。
URL并不与存储在Web服务器磁盘上的文件有直接对应关系,而是与控制器类的方法有关。
ASP.NET MVC对MVC模式中的前端控制器进行了改造,正如咱们后面要学习的,路由系统在前面,之后才是控制器。
理解MVC模式在Web场景中工作原理的便捷方法就是记住、多练!
MVC提供的是方法调用的结果,而不是动态生成的页面。
对历史不感冒的可以跳过了,不过个人建议,哪怕读不懂,哪怕一目十行,瞅一遍总是有好处的。
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控制器的具体实现。我们将继续使用前面已经创建好的项目。
如果您跳过了直接看本篇的,回头瞅瞅就行了。
在MVC入门时会遇到像先有鸡还是先有蛋这样的问题,需要理解三个部分(模型、视图和控制器),但在不理解其他部分的情况下,要深入其中一部分是很难的。
因此,再开始学习MVC时,需要首先概括地了解控制器,暂时先不管模型和视图。
讲解了控制器的基本工作原理之后,然后咱们再深入学习视图、模型和其他ASP.NET MVC开发主题。最后的文章中,咱们还会再学习高级控制器。
再开始实质性地编写代码之前,首先了解一下在一个新的项目中默认都包含那些内容。
用Internet Application模板创建的项目包含两个控制器类:
在Visual Studio的项目中,展开/Controller文件夹,打开HomeController.cs文件,如图1所示:
图1 - 控制器 HomeController.cs
注意这是一个相当简单的类,它继承了Controller基类。HomeController类的Index方法负责决定当浏览网站首页时触发的事件。
下面按照以下步骤对程序进行简单的修改,然后运行程序。
(1) 用自己想要的短语替换About方法中的“Your application description page.”,比如“Boom、ShaKaLaKa!”。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.Web.Mvc; 6 7 namespace BookStore.Controllers 8 { 9 public class HomeController : Controller 10 { 11 public ActionResult Index() 12 { 13 return View(); 14 } 15 16 public ActionResult About() 17 { 18 ViewBag.Message = "Boom、ShaKaLaKa!"; 19 20 return View(); 21 } 22 23 public ActionResult Contact() 24 { 25 ViewBag.Message = "Your contact page."; 26 27 return View(); 28 } 29 } 30 }
(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!”
现在已经创建了一个新项目并在屏幕上显示了指定的信息,接下来通过创建一个新的控制器来创建一个实际的应用程序。
首先创建一个控制器来处理有关浏览图书目录的URL。这个控制器支持一下三个功能:
创建控制器,首先需要添加一个新的StoreController类。具体方法如下:
(1) 右击“解决方案资源管理器”下项目里面的“Controller”文件夹,右键“添加 - 控制器”,如图4所示;
(2) 模板类型选择“MVC5 控制器 - 空”,如图5所示;
(3) 强控制器命名为“StoreController”,然后单击添加按钮,如图6所示。
图4 - 右键项目Controller文件夹 - 新建控制器
图5 - 选择控制器类型
图6 - 输入控制器名称
新创建的StoreController控制器已经有了一个Index()方法,下面将利用这个Index()方法实现在页面上列出图书商店里面所有图书类别的功能。
另外,还需要添加两个额外的方法来实现上面说到的其他两项功能,分别是Category()和Details()。
控制器中的这些方法(Index()、Category()、Details())成为控制器操作。
正如上述的HomeController.Index()操作方法那样,控制器操作的是响应URL请求,执行相应的操作,并向浏览器或是单击这个URL的用户做出响应。
要了解控制器操作的工作原理,可按照以下的步骤操作:
(1) 将Index()方法的返回数据类型改为 string (而不是 ActionResult );
然后将返回值 return View(); 改为 return "请求来自:Store.Index() !"; 。
修改后的StoreController.cs如下所示:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.Web.Mvc; 6 7 namespace BookStore.Controllers 8 { 9 public class StoreController : Controller 10 { 11 public string Index() 12 { 13 return "请求来自:Store.Index() !"; 14 } 15 } 16 }
(2) 添加对商店的Category()方法,将返回设置为 return "请求来自:Store.Category() !"; ;
添加浏览详细信息的Details()方法,将返回设置为 return "请求来自:Store.Details() !"; 。
控制器StoreController的完整代码如下所示:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.Web.Mvc; 6 7 namespace BookStore.Controllers 8 { 9 public class StoreController : Controller 10 { 11 public string Index() 12 { 13 return "请求来自:Store.Index() !"; 14 } 15 16 public string Category() 17 { 18 return "请求来自:Store.Category() !"; 19 } 20 21 public string Details() 22 { 23 return "请求来自:Store.Details() !"; 24 } 25 } 26 }
(3) 重新运行项目,然后浏览一下URL:
访问这些URL会调用控制器中的操作方法,然后返回相应字符串,如图7、8、9所示:
图7 - 浏览/Store
图8 - 浏览/Store/Category
图9 - 浏览/Store/Details
从以上这个姜丹实验中可以得出以下几个结论:
前面的例子返回输出的是常量字符串。 下一步就是让它们通过响应URL传进来的参数动态地执行操作。按以下步骤来实现:
(1) 把Category()操作方法修改为,查找URL传过来的查询字符串值。
可以通过在操作方法中添加一个string类型的“categoryName”参数来实现这个功能。
然后,当这个方法被调用时,ASP.NET MVC会自动将名为“categoryName”的查询字符串或表单提交参数传递给Category()操作方法。
1 public string Category(string categoryName) 2 { 3 string message = HttpUtility.HtmlEncode("Store.Category(),CategoryName=" + categoryName); 4 return message; 5 }
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/520 。
ASP.NET MVC再不需要任何额外配置的情况下可以很容易地做到这一点。
ASP.NET MVC的默认路由约定,就是将操作方法名称后面URL的这个片段( 例如上面的 /Store/Details/520 中的520)作为一个参数,该参数的名称为ID。
如果操作方法中又名为ID的参数,那么ASP.NET MVC会自动将这个URL片段作为ID参数传递过来。
1 public string Details(int id) 2 { 3 string message = "Store.Details(),ID=" + id; 4 return message; 5 }
(4) 运行应用程序,浏览到/Store/Details/520,如图11所示:
图11 - 为Details()操作方法添加id参数并访问
像前面示例演示的那样,控制器操作感觉就像是Web浏览器直接调用控制器类中对应的操作方法。
类、操作方法和参数都被具体化为URL中的特定路径片段或查询字符串,结果就是一个返回给浏览器的字符串。
这就是进行了极大的简化,而忽略了下面这些的细节:
控制器提供了很多自定义和扩展的功能,但是我们很少能用到这些内容。
在一般应用程序中,控制器通过URL被调用,然后执行自定义的代码并返回一个视图。先记住这些内容,后面我们会详细介绍关于控制器如何定义、调用和扩展的底层细节。
现在已经学习了足够的控制器知识,下面就可以与视图结合起来使用了,下一篇我们将对此进行详细的介绍。
标签:
原文地址:http://www.cnblogs.com/LonelyShadow/p/4979654.html