日期:2014-05-16 浏览次数:21032 次
Filter是很好的实现crosscutting concern 的方式,常见的crosscutting concern包括log,验证,缓存,异常处理(笔者推荐postsharp),等等。
什么是crosscutting concern?
为了更好的专注业务的实现,降低耦合,提高内聚。因此把这些concern从业务中抽离出来解决,可以更好的维护,更改和扩展。它们也构成了架构中cross-cutting的部分,可以在与业务隔离的情况下,统一编码,测试,修改。
例如AdminController :
public class AdminController : Controller { // ...instance variables and constructor public ViewResult Index() { if(!Request.IsAuthenticated) { FormsAuthentication.RedirectToLoginPage(); } } public ViewResult Create() { if(!Request.IsAuthenticated) { FormsAuthentication.RedirectToLoginPage(); } } public ViewResult Edit(int productId) { if(!Request.IsAuthenticated) { FormsAuthentication.RedirectToLoginPage(); } } }
我们的目的很明确,我需要限制这个controller的访问,只有登录的才能访问,那么我们每个action都要加上Request.IsAuthenticated.如果需要限制role,指定用户才能访问,我们就要写一个验证函数,并修改全部的action。
[Authorize] public class AdminController : Controller { public ViewResult Index() { } public ViewResult Create() { } public ViewResult Edit(int productId) { } }
好处:可以看到filter提高了代码的可读性,减少了重复。
FilterAttribute的逻辑注入在http pipeline里面,在controller之前,反射出所有controller,查找customize的attribute,如果有加Authorize,调用相应的login验证函数(后续章节会介绍),验证不通过则返回401 。
Attribute是.net 中很好应用装饰模式的例子,通过继承自System.Attribute,可以实现自己的attribute,包括class,method,property,field。目的是动态的注入property,member,和ability到相应的类中,编译之后,生成的IL已经注入了attribute要提供的能力。通常的AOP框架中有attribute和IL wave 一起使用的代码和使用方法。不熟悉的读者可以查阅相关MSDN,本章所有内容都建立在attribute有一个基本的认识上的。
MVC中四种基本的filter
Authorize Filter |
验证。进入controller或action之前 |
Action Filter |
进入action前后会被调用 |
Result Filter |
Execute result的前后会被调用 |
Exception Filter |
Filter,action,或者execute result时发生异常时被触发 |
MVC中的authorizefilter除了可以加在class上(前面演示过了),还可以针对action做filter:
public class AdminController : Controller { [Authorize] public ViewResult Index() { } [Authorize] public ViewResult Create() { } }
[Authorize(Roles="trader")] public class ExampleController : Controller { [ShowMessage]// applies to just this action [OutputCache(Duration=60)]// applies to just this action public ActionResult Index() { // ...action method body } }
public class BlockAttribute : AuthorizeAttribute { public BlockAuthAttribute() { } protected override bool AuthorizeCore(HttpContextBase httpContext) { return false; } }
作为演示,实现了一个block attribute,加上这个attribute会block所有的request。现实场景中,拿到了httpContext可以做很多事情,因为里面的对象包含的信息非常丰富。
使用:
[Block] public string Index() { return "Always block "; }
访问页面会发现:
由于我创建的是basic的项目,没有加login view在Account,因