日期:2014-05-16  浏览次数:21043 次

Asp.Net MVC 系列--进阶篇之Filter

使用Filter

 

Filter是很好的实现crosscutting concern 的方式,常见的crosscutting concern包括log,验证,缓存,异常处理(笔者推荐postsharp),等等。

 

什么是crosscutting concern?

为了更好的专注业务的实现,降低耦合,提高内聚。因此把这些concern从业务中抽离出来解决,可以更好的维护,更改和扩展。它们也构成了架构中cross-cutting的部分,可以在与业务隔离的情况下,统一编码,测试,修改。

 

言归正传--Filter

 

例如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。

应用了Filter的实现

[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

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时发生异常时被触发

 

给controller和action加 Filter:

MVC中的authorizefilter除了可以加在class上(前面演示过了),还可以针对action做filter:

public class AdminController : Controller {
 [Authorize]
public ViewResult Index() {
}
 [Authorize]
public ViewResult Create() {
}
}


也可以apply多个filter:

[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
}
}


Customize filter

代码:

 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,因