上一篇中我们随便聊了聊MVC的授权过滤器AuthorizeFilter
,其实真正关于.net平台下的认证体系之复杂远远超出了我们的想像,对权限的控制我们只能找到相对安全的做法,并不能从绝对上杜绝不安全的验证,特别是对于.net下授权权限的控制。有机会我们可以回过头来深入的探讨有关.net平台下的权限控制体系。这一篇我们继续根据mvc3的源码来学习mvc的ActionFilter
方法过滤器。
和AuthorizeFilter
原理一样,所有要用在Action
方法上的方法过滤器特性都必须继承抽象类ActionFilterAttribute
,该类是实现了不仅实现了接口FilterAttribute
,还是实现了接口IActionFilter
, IResultFilter
,接口IActionFilter
的成员如下:
public interface IActionFilter
{
void OnActionExecuting(ActionExecutingContext filterContext);
void OnActionExecuted(ActionExecutedContext filterContext);
}
OnActionExecuting
在特性标注的方法执行之前执行的方法,同理OnActionExecuted
是在特性标注的方法后执行的方法。接口IResultFilter
我们等到下章来介绍。OnActionExecuting
和OnActionExecuted
接收ActionExecutingContext
类实例作为参数,ActionExecutingContext
类的成员如下:
public virtual ActionDescriptor ActionDescriptor {get; set;}
public virtual IDictionary<string, object> ActionParameters {get; set; }
public ActionResult Result {get;set;}
看到这些成员我们该笑了,ActionDescriptor
属性我们前面已经介绍过了,通过这个属性我们可以获取执行的ActionName
和ControllerDescriptor
,进而得到Controller
的一切信息。ActionParameters
获取Action
方法执行的参数。ActionExecutingContext
类继承自类ControllerContext
,该类有以下几个重要的成员如下:
public virtual ControllerBase Controller
{
get;
set;
}
public virtual HttpContextBase HttpContext
{
get
{
if (_httpContext == null)
{
_httpContext = (_requestContext != null) ? _requestContext.HttpContext : new EmptyHttpContext();
}
return _httpContext;
}
set
{
_httpContext = value;
}
}
public virtual RouteData RouteData
{
get
{
if (_routeData == null)
{
_routeData = (_requestContext != null) ? _requestContext.RouteData : new RouteData();
}
return _routeData;
}
set
{
_routeData = value;
}
}
public RequestContext RequestContext
{
get
{
if (_requestContext == null)
{
HttpContextBase httpContext = HttpContext ?? new EmptyHttpContext();
RouteData routeData = RouteData ?? new RouteData();
_requestContext = new RequestContext(httpContext, routeData);
}
return _requestContext;
}
set
{
_requestContext = value;
}
}
这里面我们需要注意的是HttpContext
和RequestContext
这两个属性。一个是封住了有关HTTP
请求的信息,一个是封装了HttpContext
和RouteData
的请求上下文。看了那么多的微软定义的成员,我们来一个demo来演示ActionFilter
的流程。
1:新建一个mvc3
的应用程序,并创建一个控制器:
public class MyActionFilterController : Controller
{
[MyTestActionFiter]
public ActionResult Index()
{
return View();
}
public ActionResult TestIndex()
{
return View();
}
}
两个Action
对应的视图如下:
@{Layout = null; }
<!DOCTYPE html>
<html> <head><title>Index</title></head><body><div><p>这里是测试的第一个页面--Index</p>
</div> </body> </html>
@{Layout = null; }
<!DOCTYPE html>
<html> <head><title>TestIndex</title></head><body><div><p>这里是测试的第二个页面--TestIndex</p>
</div> /body></html>
紧接着我们创建一个自定义的方法过滤器MyTestActionFiter
,该类继承自ActionFilterAttribute
,具体如下:
public class MyTestActionFiter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//在动作请求之前执行的方法。
filterContext.Result = new RedirectResult("/MyActionFilter/TestIndex");
base.OnActionExecuting(filterContext);
}
}
打开F12,我们请求的是如下所示:
相应标头的信息如下:
我们可以知道我们请求Index
方法的时候,由于我们在OnActionExecuting
方法中将请求重定向(HTTP状态码:302)到了TestIndex
方法,由此可以证明OnActionExecuting
是在Action
方法之前执行。我们再来看一个demo
。我们将MyTestActionFilter
的方法改进一下:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//在动作请求之前执行的方法。
//filterContext.Result = new RedirectResult("/MyActionFilter/TestIndex");
filterContext.HttpContext.Response.Write("这是方法执行前的操作<br/>");
base.OnActionExecuting(filterContext);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
filterContext.HttpContext.Response.Write("这是方法执行之后的操作");
base.OnActionExecuted(filterContext);
}
同时将MyActionFilter
控制器改成如下:
public class MyActionFilterController : Controller
{
[MyTestActionFiter]
public void Index()
{
Response.Write("这里是测试的第一个页面--Index<br/>");
}
}
按F5运行,运行结果如下:
看到这里,大家应该对ActionFiter
的执行顺序应该有个大概的了解了吧:OnActionExecuting>Action>OnActionExecuted
。但是有一点需要注意:ActionFiter
都是在ViewResult
执行之前执行,这也是为什么我在MyActionFilter
中是直接输出内容,而不是返回ViewResult
的原因,关于这一点,我们下一章结合ResultFilter
做一个详细的解说。