第8讲:深入Controller
2010.9.8 苏鹏
内容介绍
-Action的调用与属性
预备知识
-安装Visual Studio 2010 Express
-了解ASP.Net
-了解设计模式基本概念
唤起Action
Routing把Url拿到之后回到RouteTable去匹配Url,匹配完之后就能找到Controller和Action。
-ControllerActionInvoker
它能完成四个操作:
1.找到对应的Action
2.找到当前请求对应路由发过来的参数,匹配完之后传给Action
3.调用Action方法所有的Filters(Filters是对Action的一种约束,只有经过Filters才知道Action是否真的可以执行)
4.调用ExecuteResult
Action匹配到Url
-从url中匹配Action名称
Action和Route是不见面的,他们都通过前面的ControllerActionInvoker来通讯。
它首先要在Route中找到Dictionary类,并找到Action的key,这里就能找到Action的名字。
Action选择方法
默认情况通常使用反射的方式来找到Action的工作方法。这也是要求Action方法必须都是public的原因,如果不是public就拿不到名称,也就没法完成下面的工作。
方法标准:
-不允许有NonActionAttribute标记
-构架函数,属性控制器,事件访问器不能作为制定的action方法
-继承自object的方法或者继承自Controller的方法
这三种标准是由ActionSelectorAttribute来执行验证的。
ActionNameAttribute
Action有一个命名规则,如果是一个Action方法命名为XXXCompleted,那这个方法一定要是异步调用,如果是要同步调用的方法起这种名字,就必须得在Action上面加一个别名,叫ActionName。这样ActionName匹配的时候不会匹配函数的名字,而会去匹配标记的名字。
ActionSelectorAttribute
- ActionSelectorAttribute定义
这个类的功能是验证IsValidFromRequest作最后匹配,如果匹配内容是False,这个Action就会从list中消除,如果匹配为True,这个Action就会被验证。最后我们的list会剩下一个匹配结果,这个函数就是最后被用来调用的。如果遍历之后发现匹配结果多于1个,就会抛出一个异常。如果遍历完之后发现一个Action都没有匹配上,也会抛出一个异常。
AcceptVerbsAttribute
它是最简单的一个Filters,它是混合了两种Http请求的一个验证方法。这就可以验证请求是否符合针对的Action,这种方式也可以解决函数的重名问题。
模拟Rest请求
HttpPostAttribute 对应创建模式
HttpPutAttribute 对应更新模式
HttpGetAttribute 对应读取模式
HttpDeleteAttribute 对应删除模式
有了这样的对应,我们的CRUD(Create、Read、Update、Delete)就可以用一个Url完成了。这样就进一步规范了Rest架构Web应用程序可用的一致性接口,并且对资源的操作取决于Http的方式。
映射参数
三种传参方式:
1.RequestFormCollection
2.RouteData(推荐)
3.QueryString
一旦Action方法确定了之后,就需要映射Action的参数。
调用Action
-使用异步的Action
IIS在启动的时候会有一个线程池,当用户发起一个请求的时候,IIS从线程池中找出一个空闲的线程,说你来响应这个请求吧,这个线程就会被设计为响应用户的请求。比如用户请求花了2秒时间完成,服务器端就会在2秒内实现阻塞,等待请求的完成,这个线程既是响应用户请求的线程,又是返回用户结果的线程。线程执行完操作返回给用户端之后,就回到线程池,因为它再次空闲了。默认情况下由于线程池的空闲线程比较多,这样做没什么影响。但是如果请求特别多,IIS吃紧,IIS就没法处理您的请求了,这时就会出现网络访问繁忙的错误。
因此,我们有时候需要异步的方式来工作。当服务器端拿到请求时,Action就唤醒一个线程,线程开启工作。线程开启工作之后就回到线程池了,工作就由后台其它的工作线程去做。工作结束之后MVC架构就会告诉IIS说我的工作运行完了,你再给我一个线程,我就可以把结果返回给你。这样的方式用户感觉没有区别,但是服务器的线程空闲比例会相对较高。
同步与异步的比较
使用同步方式
1.操作短小迅捷
异步操作在返回结果的时候需要再次获得线程,这个性能消耗也是要考虑的。
2.要求高可测试性
异步情况Action在发送和返回的是不同线程,这在测试的时候很难实现,状态没法追踪。
3.这个操作要求高CPU而不是高IO
使用异步操作
1.通过测试发现该操作是网站应用性能瓶颈
这种阻塞瓶颈的解决方法,除了异步Action,还有一种方法:OutputCahce,可以把Action的结果用OutputCahce缓存。这种缓存能有效缩短用户的等待时间,把用户发送的重复请求用缓存结果返回,这样可能数据不能及时保持最新,但是效果还是不错的。而异步请求对于用户来说还是没有区别的,用户该等多久还是要等多久。
2.对并行性有高要求
3.对这个操作要求高IO而不是高CPU
IO操作是整个性能下降最容易产生问题的地方,因为IO访问独占性,IO访问本身是由操作系统转发的。
编写异步Action
同步访问
异步访问
异步访问的Controller要继承自AsyncController。Action名字的结尾也只能是Async和Completed,这两个Action是一对,前者是响应Action请求,后者是返回数据给用户。这两者不能作为Action直接被调用。
在异步模式下参数传递方式也不同,需要用AsynvManager.Parameters字典类保存结果以便返回。因为同步是一个线程,而异步是两个线程,第一个线程结束之后,数据就没有了,我必须使用一个中间变量在两个线程之间传递数据,这个中间变量就是AsynvManager,它专门用来监视多变量的实现。
OutstandingOperation.Increment方法用来管理MVC当前的请求,这个操作非常重要,它主要是让MVC架构知道当前有多少个操作处于挂起状态,一旦把工作交给Action的后台以后,我们就不管了,OutstandingOperation每完成一个对应的Action,它就会-1,当它变成0的时候,我们就知道,这个Controller的工作已经完成了。对应的Completed方法就会被调用了。
并行操作的性能
同步访问
异步访问
分析一下异步的操作。OutstandingOperation.Increment(3),说明现在又3个操作。每个操作一旦完成,就需要调用OutstandingOperation.Decrement把操作数-1。全部做完之后,有一个Completed函数,它去把当前所有信息拿到,生成并返回。上面的三个操作都是并行的,因此执行的总时间是三个操作中最长的时间,而同步操作的执行总时间是三个操作的时间之和。这就是异步访问中的并行优势,如果一个Action有多个内容,就应该用异步并行来做。
对异步请求使用标签
异步Action的标签不能加在Completed方法之上。
超时
AsyncTimeout默认情况45秒超时。Timeout标签可以更改超时时间,NoAsync是永远不超时(不推荐)。如果直接指定在Controller上表示里面每个Action都默认加了这个标签。
关于异步方法调用的附加说明
如果一定要用Completed后缀的同步方法,需要使用别名
如果是Action方法是异步的,但是方法里面的一些步骤需要同步,就可以用Begin和End成对的函数来做
需要注意的一点是,Html.Action和Html.RenderAction是可以指向异步方法的,但是这个方法会以同步方式去调用。
更新Model层UpdateModel
这里更新之前首先验证ModelState是否可用,可用才更新,更新之后Redirect到Edit的Action。这里选择Redirect到其它地方,而不是直接返回一个View层的原因,是一个小技巧的时候。有时候用户提交数据的时候,看见没反应,就回去刷新,刷新便又会提交一条数据,当Post请求过来的时候,一旦完成它,就会跳到别的Edit,就可以编辑数据或者做一些别的相应的请求,而它每次刷新的时候,会导致ModelState不可用,这个时候只把当前请求结果返回,避免用户使用鼠标刷新页面导致重复数据提交。
验证数据
这个是写在Model层的。
安全性
永远不要不加处理的使用用户的输入(使用Html.Encode方式是很有必要的)
总结
-Action的调用与属性
2010.10.1