快速入门系列--MVC--05行为

Action执行包含内容比较多,主要有同步/异步Action的概念和执行过程,Authorationfilter, ActionFiltor, ResultFilter, ExceptionFilter等四个主要过滤器类型的执行过程。首先介绍异步的Action,之前学习Controller的时候已经知道默认情况下Controller的执行是异步的,在不继承异步Controller的情况,我们代码中的方法一般是同步的Action,我们可以通过使用Task<ActionResult>类型的返回值和在Action方法使用Task.Factory.StartNew()等方法来调用异步的Action,主要用于I/O绑定等操作。ASP.NET是通过线程池的机制来处理并发的HTTP的请求的,这种方式的优点是:工作线程的重用,减少线程的创建和释放;限制工作线程数量,避免高并发时服务器的崩溃。这里省略MVC4版本前的老式异步Action调用,Task返回值的Action如下所示:

 

在上代码中,可以看到一个AsyncManager类,它起到了在异步操作和回调操作间传递参数的作用。这是一个关于异步操作很重要的类型,其属性OutstandingOperatons是一个异步操作计数器,类似信号量的概念,用Increment设置初始值,当一个或多个异步操作完成时递减,为0时表示有所操作已完成,出发Completed事件,调用Finish方法。需要注意的细节是设置初始值的方法需要放在异步操作的外部,异步操作的超时时间可以通过AsyncTimeoutAttribute特性的Duration属性来设置。

接下来,介绍Action的执行过程,在Controller中,包括Model绑定和验证在内的整个Action的执行是通过一个名为ActionInvoker的组件来完成的,也包含同步异步两个版本,实现类为ControllerActionInvoker和AsyncControllerActionInvoker。这个简单介绍一下Controller在选择ActionInvoker时的步骤:通过DependencyResolver以IAsyncAcionInvoker查;以IActionInvoker查;创建异步类型作为默认。不同的ControllerActionInvoker会创建其对应的ControllerDescriptor实现类,包含对应类型的ActionDescriptor。还有一点需要注意的是,Dependency默认使用会将反射创建的对象缓存到CurrentCache属性中,而不会使用当前新设置的映射重新获取。若想在程序中修改,需要手动的清空CurrentCache所对应类型中的_cache字段,部分代码如下所示:

 

在介绍筛选器的执行之前,再回顾一下相关过程,目标Action方法的最终执行是由被激活Controller的ActionInvoker决定,ActionInvoker通过调用对应的ActionDesciptor来执行被它描述的Action。筛选器使用面向切面概念(AOP)的实现,它会在在Action方法执行的前后自动执行,主要包含非业务逻辑的实现,例如授权,异常处理等。Filter作为基类包含FilterScope和Order属性,Scope包括First、Global、Controller、Action和Last,Order越小优先级越高,默认值为-1。同样Filter也有相应的Provider类,框架中原生的有FilterAttributeFilterProvider,ControllerInstanceFilterProvider和GlobalFilterCollection,简介如下表所示:

类型 简介
FilterAttribute, FilterAttributeFilterProvider 方法GetFilter得到的每个Filter,对应的FilterAttribute特性作为其Instance属性,Scope属性取决于FilterAttribute特性是应用在Controller类型上还是Action方法上。
Controller, ControllerInstanceFilterProvider Controller实现了IActionFilter,IAuthorization等四接口,本身就是一个筛选器,通过ControllerInstanceFilterProvider类型来表示针对Controller对象这种特殊筛选器的Filter。它的GetFilter方法根据ControllerContext获得对应Controller,并作为Filter的Instance属性,其Scope为First,Order为Int32.MinValue,默认最先执行。
GlobalFilterCollection 全局的Filter通过GlobalFilter.Filters.Add方式来添加,默认Scope为Global。

在筛选器的执行顺序上,遵循先Order排序,再Scope排序,若同一筛选器特性标注在不同Scope上且AllowMultiple为false时,会选中最后的一个执行。框架使用一个FilterInfo类型统一管理内置的筛选器,之后开始按照执行顺序详细介绍各个内置的筛选器。

AuthorizationFilter,实现IAuthorizationFilter的OnAuthoration方法用于实现授权操作,成功后继续Action后续工作(Model绑定,验证,Action的执行),失败后AuthorizationContext对象的Result属性回复一个"401,Unauthorized"相应或者重定向到错误页面。它所对应的几个实现IAuthorizationFilter接口的如下表所示:

类型 简述与例子
AuthrizeAttribute 多个Authorize特性间是"逻辑与"得关系,如下代码任何用户均无法访问。[Authorize(Users = "Xixi", Roles="Admin")] [Authorize(Users = "XiongEr", Roles = "Admin")] public void CannotCall() { }
RequiredHttpsAttribute 要求请求为HTTPS形式(HttpRequest.IsSecureConnection),不满足时,如果是GET方式请求返回RedirectResult重定向请求,如果是其他方式抛出异常。
ValidateInputAttribute 在Controller, Action级别上针对整个请求决定输入参数是否进行验证。例如在QueryString中放入"<script></script>"
ValidateAntiForgeryTokenAttribute 防止CSRF(Cross-Site Request Forgery)跨站请求伪造网络攻击,如果说XSS(Cross Site Script)是利用了用户对网站的信任,那个CSRF就是利用了站点对认证用户的信任。在之后的内容中,将继续介绍CSRF的原理和框架的预防方法。
ChildActionOnlyAttribute 一般用于生成组成页面的某部分HTML,若非子Action则抛出异常。(通过DataTokens中是否包含ParentActionViewContext判断)

接下来用蒋老师介绍的简单例子来解释CSRF的原理,假设我们奖励一个博客应用,作为博主的我们可以发表博文,而一般用户(包括匿名)可以评论。除此之外注册用户可以修改自己的绑定Email,我们将授权特性加在该Action上,看起来应该OK了,但仍然有漏洞可钻。

从上图可知,通过跳转攻击者获得用户安全令牌,通过了授权验证,说明CSRF是一种隐蔽且危害巨大的攻击,框架通过ValidateAntiForgeryTokenAttribute结合HtmlHelper的AntiForgeryToken方法有效解决了这个问题。在View中通过调用AntiForgeryToken方法,在页面中生一个值为防伪令牌字符串的hidden类型的<input>元素,并且设置一个具有HttpOnly的Cookie。防伪令牌值通过Salt,Creation,Username等内容计算得出。Cookie的名称通过应用路径base64编码值加上_RequestVerificationToken组合而成。对于加入防伪令牌的View在第一次访问或者Cookie不存在时,创建Cookie并设置HttpOnly标签,这样浏览器就无法通过脚本获得Cookie,保证了Cookie的安全。再次请求时,解密和反序列化Hidden与Cookie中相关值,比较属性即可。

ActionFilter之前介绍过的实现类包括AsyncTimeoutAttribute等,允许我们对Action执行前后添加一些额外操作,通过Result属性响应其请求。筛选器中OnActionExecuting与OnActionExecuted的执行顺序相反。正向执行时,一旦某一个ActionFilter将AcionExecuteingContext的Result设置为ActionResult对象,后续ActionFilter和目标Action将不会执行。而在逆向执行ActionFilter链时在ActionExecutedContext中设置Result不受影响,如下图所示:

ActionFilter链的异常处理过程通过对应的上下文类的Exception对象传递,ExceptionHanlded属性表明异常是否已被处理。

ExceptionFilter既可以处理ActionFilter最终抛出的异常,还可以处理ResultFilter抛出的异常。其中实现类HanldeErrorAttribute用于针对具体的异常类型来呈现对应的错误页面。同时由于ExceptionFilter链的反向执行特性,需要设置Order属性使得具体的HanldeErrorAttribute优先执行。

需要注意的一点是,HandleErrorAttribute只有在允许自定义错误时才有效, <customErrors mode="On"/>

蒋老师在书中提到,异常处理是程序员最熟悉也最难掌握的一块概念了,我确实也有这样的感受,比如说一个异常类型到底"谁来管,该怎么管,管不住怎么办",很像法制建设,需要一定的规定,但软件开发中还未有相关的通用规则。由于异常处理往往是场景驱动的,就需要一个灵活可配置的处理框架进行管理,例如微软企业库Entlib的Exception Handling Application Block(EHAB)。该库提供一种基于"策略"的异常处理方式。之后还提供了一个自动化处理异常的思路,即通过配置,自动生成try/catch过程。

简单来说就是:

异常处理策略=异常类型+异常处理器+异常后续处理方式,例子如下所示:

 

相应的调用方式为:

 

ResultFilter用于控制ActionResult的执行,属于在Action方法执行过后对ActionResult执行过程的控制,也就是对视图渲染的控制了,内容与ActionFilter相似,就不介绍了。

注:本文主要供自己学习,不妥之处望见谅。

参考资料:

[1]蒋金楠. ASP.NET MVC4框架揭秘[M]. 上海:电子工业出版社, 2012. 320-389

时间: 2024-10-10 01:10:04

快速入门系列--MVC--05行为的相关文章

快速入门系列--MVC--01概述

虽然使用MVC已经不少年,相关技术的学习进行了多次,但是很多技术思路的理解其实都不够深入.其实就在MVC框架中有很多设计模式和设计思路的体现,例如DependencyResolver类就包含我们常见的DI依赖注入概念和注册表模式(GetService)等内容,ExceptionFilter等过滤器就体现AOP的概念,整个MVC内置了一个IOC容器,基本上所有的框架类的对象都是通过这种方式来创建的.此外,一直觉得很j2ee的spring很棒,其实如果大家很熟悉EHAB(微软企业开发库)的话,就会发

快速入门系列--WebAPI--03框架你值得拥有

接下来进入的是俺在ASP.NET学习中最重要的WebAPI部分,在现在流行的互联网场景下,WebAPI可以和HTML5.单页应用程序SPA等技术和理念很好的结合在一起.所谓ASP.NET WebAPI,其核心概念就是构建REST风格的Web服务,把一起数据视为资源,无论是服务请求或者是数据操作,与以前的SOAP和XML-RPC架构风格有很大不同.说道这,很多读者可能想到WCF中不是早都有了REST风格的服务么,为什么还需要这个WebAPI?确实如此,不过WCF中的该类型服务显得比较复杂,因为其通

快速入门系列--WebAPI--01基础

ASP.NET MVC和WebAPI已经是.NET Web部分的主流,刚开始时两个公用同一个管道,之后为了更加的轻量化(WebAPI是对WCF Restful的轻量化),WebAPI使用了新的管道,因此两者相关类的命名空间有细微差异,在使用时需要注意. WebAPI学习系列目录如下,欢迎您的阅读! 快速入门系列--WebAPI--01基础 快速入门系列--WebAPI--02进阶 快速入门系列--WebAPI--03框架你值得拥有 快速入门系列--WebAPI--04在老版本MVC4下的调整 W

WPF快速入门系列(1)——WPF布局概览

一.引言 关于WPF早在一年前就已经看过<深入浅出WPF>这本书,当时看完之后由于没有做笔记,以至于我现在又重新捡起来并记录下学习的过程,本系列将是一个WPF快速入门系列,主要介绍WPF中主要的几个不同的特性,如依赖属性.命令.路由事件等. 在正式介绍之前,我还想分享下为什么我又要重新捡起来WPF呢?之前没有记录下来的原来主要是打算走互联网方向的,后面发现互联网方向经常加班,又累,有时候忙的连自己写了什么都不知道的,所以后面机缘巧合地进了一家外企,在外企不像互联网行业那样,比较清楚,有更多的时

C语言快速入门系列(六)

C语言快速入门系列(五) C语言指针加强 本节引言: 上一节我们对C语言中的指针进行了初步的了解,学习了指针的定义,与普通变量 一维数组,二维数组,字符串之间的使用!在本节中我们将会学习一些新的知识点, 函数,结构体与共用体,枚举类型以及类型定义符typedef! 本节学习路线图: 本节正文 函数 ps:空函数就是什么都不做的函数,开发过程中不需要马上实现的,先写空函数!简单的空函数:void abc(){   } 结构体 共用体: 代码示例2: 建立一个共用体类型,当输入的时学生类型时,要求输

C语言快速入门系列(一)

C语言快速入门系列(一)  本系列引言: 本教程的宗旨是将C语言入门的内容进行关键知识点的提纯,将一些笼统的废话去除; 再进行压缩,然后将本章的关键知识点做成路线图的,可以更加方便地掌握学习的方向; 最后提供相关的代码示例以及详细注释,可以帮助学者更快地上手C语言! 如果对本教程有什么建议和缺点纰漏的,欢迎指出,不胜感激! 本节学习路线图: 正文: 1.计算机与程序设计语言的关系: 答:计算机是由硬件与软件系统组成,硬件==>物质基础;软件==>灵魂; 如果脱离了软件,计算机就只是一台什么都做

WPF快速入门系列(4)——深入解析WPF绑定

一.引言 WPF绑定使得原本需要多行代码实现的功能,现在只需要简单的XAML代码就可以完成之前多行后台代码实现的功能.WPF绑定可以理解为一种关系,该关系告诉WPF从一个源对象提取一些信息,并将这些信息来设置目标对象的属性.目标属性总是依赖属性.然而,源对象可以是任何内容,可以是一个WPF元素.或ADO.NET数据对象或自定义的数据对象等.下面详细介绍了WPF绑定中的相关知识点. 二.绑定元素对象 2.1 如何实现绑定元素对象 这里首先介绍绑定最简单的情况——绑定元素对象,即数据源是一个WPF元

C语言快速入门系列(五)

C语言快速入门系列(五) C语言指针初涉                                           ------转载请注明出处:coder-pig 本节引言: 上一节我们对C语言复合数据类型中的数组进行了解析,在本节中,我们会对C语言复合数据类型中的 重点,C语言的灵魂-----指针进行学习!使用指针的好处:利用指针可以表示与使用复杂的数据结构; 更加方便地使用我们的数组与字符串;可以像汇编语言一样直接处理内存单元地址;可以动态地进行内存空间 分配,C语言指针是重点,同

C语言快速入门系列(九)

C语言快速入门系列(九)                                               ---转载请注明出处:coder-pig C语言知识点拾遗 本节引言: C语言系列已经接近尾声了,在前面八节的学习中,我们学会了C的基本语法,基本数据类型, 三种程序结构(顺序,判断,循环),数组,函数,指针,结构体,共用体,位运算,文件等内容, 本节将对前面没有讲的C的遗漏知识点进行补充,当然发现有那些的遗漏的知识点也会进行更新! 谢谢大家一直以来的支持,说了这么多的理论,缺的

C语言快速入门系列(七)

C语言快速入门系列(七) C语言指针进阶 本章引言: 在前面第5节中我们对C语言的指针进行了初步的学习理解;作为C语言的灵魂, C指针肯定没那么简单,在这一节中,我们将会对指针进行进一步的学习,比如二级指针, 指针数组,内存分配和const修饰指针常量等!下面就请大家跟随笔者的脚步,对 C指针神秘的一面进行进一步的解析吧! 本节学习路线图: 函数与指针: ①指针作为函数的形参: ②指向函数的指针: ③指针函数: ④带参数的主函数 ps:该代码的运行:先要编译生成exe文件后,来到exe所在文件目