ASP.NET MVC 4.0的Action Filter

时间:2022-05-25 04:37:19

有时候你想在调用action方法之前或者action方法之后处理一些逻辑,为了支持这个,ASP.NET MVC允许你自定义创建action过滤器。Action过滤器是自定义的Attributes,用来标记添加Action方法之前或者Action方法之后的行为到控制器类中的Action方法中。

什么情况下可能会用到action过滤的地方

  • 日志,异常处理
  • 身份验证和授权 - 限制用户的访问
  • 输出缓存 - 保存一个Action的结果
  • 网络爬虫的过滤
  • 本地化
  • 动态Action - 将一个Action注入到控制器中

ASP.NET MVC 4.0 Framework支持四种不同类型的Filter

  1. Authorization filters – 实现IAuthorizationFilter接口的属性.
  2. Action filters – 实现IActionFilter接口的属性.
  3. Result filters – 实现IResultFilter接口的属性.
  4. Exception filters – 实现IExceptionFilter接口的属性.

ASP.NET 内置的Filter默认的执行顺序按上面的列表中顺序进行。如验证(authorization)Filter永远都是最开始执行的,异常(exception)Filter永远都是最后执行的,当然你也可以根据需要通过Order属性设定过滤器执行的顺序。

Action过滤器的执行顺序

每一个Action过滤器都有一个 Order 属性,用来决定Action过滤器在该范围内的执行顺序。Order属性必需是0(默认值)或者更大的整数值。省略Order属性则会给该过滤器的Order值为 -1, 表明为指明顺序。任何一个在同一范围的Action过滤器Order设为 -1 的都将按不确定的顺序执行,单在此之前过滤器有一个特定的顺序(注:下面会说到).

当设置Order属性的值的时候,必需指定一个唯一的值。如果两个或者更多的Action过滤器具有相同的Order属性值,将会抛出一个异常。

 [Filter1(Order = )]
[Filter2(Order = )]
[Filter3(Order = )]
public ActionResult Index()
{
return View();
}

Filter的执行顺序为:Filter3 => Filter1 => Filter2.

用户自定义ActionFilter

为了让用户更简单的创建一个自定义action filter,ASP.NET MVC 4.0 Framework提供了一个基类ActionFilterAttribute,这个类实现了IActionFilter和IResultFilter接口,并且继承了Filter类。

这里的术语并不完全一致,从技术上说,这个类继承ActionFitlerAttribute,并且同时实现了action filter和result filter接口,但是从宽松意义上说,在ASP.NET MVC Framework中,任何实现filter的类型都是action filter。

ActionFilterAttribute类有以下的方法可以重写:

  • OnActionExecuting – 在controller action执行之前调用
  • OnActionExecuted – 在controller action执行之后调用
  • OnResultExecuting – 在controller action result执行之前调用
  • OnResultExecuted – 在controller action result执行之后调用

以下是这几个方法的执行顺序:

OnActionExecuting()-> Action execute & return View() ->OnActionExecuted() ->OnResultExecuting() -> Render View() ->OnResultExecuted()

举个例子:检查登录是否为管理员身份

     public class AdminFilter : ActionFilterAttribute //自定义AdminFilter继承ActionFilterAttritube
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!Convert.ToBoolean(filterContext.HttpContext.Session["IsAdmin"]))
{
//如果不是管理员,提示如下content
filterContext.Result = new ContentResult()
{
Content = "Unauthorized to access specified resource."
};
}
}
}
         //引用自定义过滤器
[AdminFilter]
public ActionResult AddNew()
{
CreateEmployeeViewModel cvm = new CreateEmployeeViewModel();
return View("CreateEmployee",cvm);
}

用户自定义带参数ActionFilter

     public class AdminFilter : ActionFilterAttribute
{
public string Message { get; set; } //增加message属性
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!Convert.ToBoolean(filterContext.HttpContext.Session["IsAdmin"]))
{
//直接提示content内容,不会执行action
filterContext.Result = new ContentResult()
{
//action调用过滤器时,得到message值
Content = Message + "Unauthorized to access specified resource."
};
}
}
}
         [AdminFilter(Message = "GetAddNewLink")] //传入message参数
public ActionResult GetAddNewLink()
{
if(Convert.ToBoolean(Session["IsAdmin"]))
{
return PartialView("AddNewLink");
}
else
{
return new EmptyResult();
} }

自定义过滤器加入到全局过滤器

有时我们想有些公共的方法需要每个Action都执行,但是又不想再每一个Controller上都打上Action标签,怎么办?幸好Asp.Net 从MVC3带来了一个美好的东西,全局Filter。而怎么注册全局Filter呢?答案就在Global.asax中。让我们看以下代码,我是如何将上面我们定义的AdminFilter注册到全局Filter中。

App_Start /FilterConfig.cs

     public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new AdminFilter() { Message = "global" });
}
}

补充说明:

如果标签打到Controller上的话,AdminFilter将作用到Controller下的所有的Action。

  1.默认情况下Action上打了某个自定义标签后,虽然在Controller上也打上了此标签,但它只有Action上的标签起作用了。
  2.如果Action没有打上该标签,那么Controller上的标签便会被执行。

如果想让Action上的标签执行一次,然后Controller上的标签也执行一次,那么应该如何操作呢?

   我们只需在FilterAttribute类的定义上打上标记[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]即可【下面类的最上面红色字体部分】,也就是让其成为可以多次执行的Action。代码如下:

     [AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
public class AdminFilter : ActionFilterAttribute
{
........
}