先来看看一个例子演示过滤器有什么用:

public class AdminController : Controller {
// ... instance variables and constructor
public ViewResult Index() {
if (!Request.IsAuthenticated) {
FormsAuthentication.RedirectToLoginPage();
}
// ...rest of action method
}
public ViewResult Create() {
if (!Request.IsAuthenticated) {
FormsAuthentication.RedirectToLoginPage();
}
// ...rest of action method
}
...

AdminController控制器的众多Action中我们都需要判定当前验证用户,这里有很多重复的代码,我们可以简化为:

[Authorize]
public class AdminController : Controller {
// ... instance variables and constructor
public ViewResult Index() {
// ...rest of action method
}
public ViewResult Create() {
// ...rest of action method
}
...

Authorize特性类AuthorizeAttribute就称作MVC的Filter,它在横向为MVC框架扩展功能,让我们可以更方便的处理日志、授权、缓存等而不影响纵向主体功能。

MVC常用的滤器类型:

  • Authorization:实现IAuthorizationFilter接口,默认实现类AuthorizeAttribute,在调用Action方法前首先处理认证信息。
  • Action:实现IActionFilter接口,默认实现类ActionFilterAttribute,在运行Action前后调用实现一些额外的动作。
  • Result:实现IResultFilter接口,默认实现类ActionFilterAttribute,在action result运行前后调用实现额外的动作。
  • Exception:实现IExceptionFilter接口,默认实现类HandleErrorAttribute,仅在其他过滤器或者action方法或者action result抛出异常时调用。

过滤器可以应用在整个控制器类上,也可以单对某个Action方法,当然也可以是同时应用多个过滤器:

[Authorize(Roles="trader")] // applies to all actions
public class ExampleController : Controller {
[ShowMessage] // applies to just this action
[OutputCache(Duration=60)] // applies to just this action
public ActionResult Index() {
// ... action method body
}
}

Authorization过滤器

Authorization过滤器用于控制仅授权的用户可以调用某个Action方法,它必须实现IAuthorizationFilter接口:

namespace System.Web.Mvc {
public interface IAuthorizationFilter {
void OnAuthorization(AuthorizationContext filterContext);
}
}

处理安全方面的代码必须谨慎全面,一般我们不要直接实现接口IAuthorizationFilter,而从AuthorizeAttribute扩展自定义类:

public class CustomAuthAttribute : AuthorizeAttribute {
  private bool localAllowed;
  public CustomAuthAttribute(bool allowedParam) {
    localAllowed = allowedParam;
  }
  protected override bool AuthorizeCore(HttpContextBase httpContext) {
    if (httpContext.Request.IsLocal) {
    return localAllowed;
    } else {
    return true;
    }
  }
}

这里定义了CustomAuthAttribute过滤器,如果请求来自于非本机总是允许,如果是本机请求则视传入参数allowedParam而定:

public class HomeController : Controller {
  [CustomAuth(false)]
  public string Index() {
    return "This is the Index action on the Home controller";
  }
}

默认实现AuthorizeAttribute足够应付多数授权功能限制,我们可以传入参数限制访问的用户或者角色:

[Authorize(Users = "adam, steve, jacqui", Roles = "admin")] 

需要注意的是AuthorizeAttribute仅仅负责授权,而用户的认证则依赖于ASP.NET的认证机制。

Exception过滤器

Exception过滤器需要实现IExceptionFilter接口:

namespace System.Web.Mvc {
public interface IExceptionFilter {
void OnException(ExceptionContext filterContext);
}
}

从filterContext我们可以获取很多相关信息,比如Controller、HttpContext、IsChildAction、 RouteData、Result、Exception、ExceptionHandled等。异常的具体信息我们可以从Exception获取,我们设 置ExceptionHandled为true报告异常已经处理,在设置为true之前最好检查异常是否已经被action方法上其他的过滤器处理,以避 免重复的错误纠正动作。如果异常未被处理(ExceptionHandled!=true),MVC框架使用默认的异常处理程序显示ASP.NET的黄屏 错误页面。

我们可以创建自定义的异常过滤器:

 public class RangeExceptionAttribute : FilterAttribute, IExceptionFilter {

        public void OnException(ExceptionContext filterContext) {

            if (!filterContext.ExceptionHandled &&
filterContext.Exception is ArgumentOutOfRangeException) { int val = (int)(((ArgumentOutOfRangeException)filterContext.Exception).ActualValue); //filterContext.Result = new RedirectResult("~/Content/RangeErrorPage.html");
filterContext.Result = new ViewResult {
ViewName = "RangeError",
ViewData = new ViewDataDictionary<int>(val)
};
filterContext.ExceptionHandled = true;
}
}
}

注意这里RangeExceptionAttribute除了实现IExceptionFilter接口还从FilterAttribute继承, 这是因为MVC的过滤器类还必须实现IMvcFilter接口,这里我们没有直接实现IMvcFilter接口,改为从默认封装类 FilterAttribute继承。如下使用这个自定义过滤器:

...
[RangeException]
public string RangeTest(int id) {
  if (id > 100) {
  return String.Format("The id value is: {0}", id);
  } else {
  throw new ArgumentOutOfRangeException("id");
  }
}
...

在发生异常时过滤器会将我们重定向到RangeError视图。

通常我们不需要创建自己的异常处理器,而使用MVC提供的默认过滤器HandleErrorAttribute:

[HandleError(ExceptionType = typeof(ArgumentOutOfRangeException), View = "RangeError",Master="")]

属性ExceptionType指定要处理的异常类型,如果不指定则处理所有异常类型;view指定错误时要渲染的视;master指定所用的页面布局。

在使用HandleErrorAttribute过滤前我们必须在Web.config的<System.Web>一节启用CusomErrors:

<customErrors mode="On" defaultRedirect="/Content/RangeErrorPage.html"/> 

默认customErros为RemoteOnly,defaultRedirect指定一个默认的错误页面。

Action过滤器

Action过滤器必须实现IActionFilter接口:

namespace System.Web.Mvc {
public interface IActionFilter {
  void OnActionExecuting(ActionExecutingContext filterContext);
  void OnActionExecuted(ActionExecutedContext filterContext);
  }
}

OnActionExecuting()在调用action方法前调用,OnActionExecuted()则在调用action方法后调用。

OnActionExecuting的一个实现例子:

public class CustomActionAttribute : FilterAttribute, IActionFilter {

        public void OnActionExecuting(ActionExecutingContext filterContext) {
if (filterContext.HttpContext.Request.IsLocal) {
filterContext.Result = new HttpNotFoundResult();
}
} public void OnActionExecuted(ActionExecutedContext filterContext) {
// not yet implemented
}
}

这里我们仅实现了OnActionExecuting方法,在从本地请求任何应用此过滤器的action方法时返回404错误。

OnActionExecuted的一个例子:

 public class ProfileActionAttribute : FilterAttribute, IActionFilter {
private Stopwatch timer; public void OnActionExecuting(ActionExecutingContext filterContext) {
timer = Stopwatch.StartNew();
} public void OnActionExecuted(ActionExecutedContext filterContext) {
timer.Stop();
if (filterContext.Exception == null) {
filterContext.HttpContext.Response.Write(
string.Format("<div>profile result method elapsed time: {0}</div>",
timer.Elapsed.TotalSeconds));
}
}
}

在调用action方法前我们启动计时器,在action方法调用后停止计时器并输出计时器所计action方法运行时长。

Result过滤器

Result过滤器实现IResultFilter接口:

namespace System.Web.Mvc {
public interface IResultFilter {
void OnResultExecuting(ResultExecutingContext filterContext);
void OnResultExecuted(ResultExecutedContext filterContext);
}
}

Result过滤器操作的是action方法返回结果,有意思的是即使action方法返回void所应用的Result过滤器也会动作。

类似上面的ProfileAction过滤器我们可以对Result运行计时:

public class ProfileResultAttribute : FilterAttribute, IResultFilter {
private Stopwatch timer; public void OnResultExecuting(ResultExecutingContext filterContext) {
timer = Stopwatch.StartNew();
} public void OnResultExecuted(ResultExecutedContext filterContext) {
timer.Stop();
filterContext.HttpContext.Response.Write(
string.Format("<div>Result elapsed time: {0}</div>",
timer.Elapsed.TotalSeconds));
}
}

内建的Result过滤器类ActionFilterAttribute

MVC为我们提供了ActionFilterAttribute类,它同时实现了action和result过滤器接口:

public abstract class ActionFilterAttribute : FilterAttribute, IActionFilter,
IResultFilter{
public virtual void OnActionExecuting(ActionExecutingContext filterContext) {
}
public virtual void OnActionExecuted(ActionExecutedContext filterContext) {
}
public virtual void OnResultExecuting(ResultExecutingContext filterContext) {
}
public virtual void OnResultExecuted(ResultExecutedContext filterContext) {
}
}
}

我们只需要继承该类并重载需要的方法,比如:

public class ProfileAllAttribute : ActionFilterAttribute {
private Stopwatch timer; public override void OnActionExecuting(ActionExecutingContext filterContext) {
timer = Stopwatch.StartNew();
} public override void OnResultExecuted(ResultExecutedContext filterContext) {
timer.Stop();
filterContext.HttpContext.Response.Write(
string.Format("<div>Total elapsed time: {0}</div>",
timer.Elapsed.TotalSeconds));
}
}

Controller类的过滤器支持

MVC的Controller类内部实现了IAuthorizationFilter、IActionFilter、IResultFilter、IExceptionFilte四个接口,并提供OnXXX的虚函数供调用,比如:

    public class HomeController : Controller {
private Stopwatch timer; protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
timer = Stopwatch.StartNew();
} protected override void OnResultExecuted(ResultExecutedContext filterContext)
{
timer.Stop();
filterContext.HttpContext.Response.Write(
string.Format("<div>Total elapsed time: {0}</div>",
timer.Elapsed.TotalSeconds));
} ...

全局过滤器

全局过滤器应用于应用程序内所有控制器的所有action方法,我们在App_Start/FilterConfig.cs可以注册全局过滤器:

public class FilterConfig {
public static void RegisterGlobalFilters(GlobalFilterCollection filters) {
filters.Add(new HandleErrorAttribute());
filters.Add(new ProfileAllAttribute());
}
}

HandleErrorAttribute是VS为我们默认添加的,用于未处理异常错误时显示/Views/Shared /Error.cshtml页面;ProfileAllAttribute则是我们添加的自定义过滤器,运行任何action方法时都会调用这个过滤器。

其他MVC内建过滤器

MVC框架还内建提供以下过滤器:

  • RequireHttps:指示必须以HTTPS访问action方法,仅用于HTTP get方法
  • OutputCache:缓存action方法的结果
  • ValidateInput和ValidationAntiForgeryToken:安全授权相关的过滤器
  • AsnycTimeOut和NoAsyncTimeout:用于异步控制器
  • ChildActionOnlyAttribute:用于授权Html.Action或者Html.RenderAction调用子action方法

这些过滤器的使用方法可以参见MSDN。

过滤器的运行顺序

过滤器的运行按先后顺序是:authorization过滤器、action过滤器、result过滤器,期间任何时刻发生未处理异常调用异常处理 器。这是针对不同类型的过滤器,但是如果所应用的是同一类的过滤器呢?MVC默认并不保证同类型过滤器的调用程序,也就是说很可能并非按照出现在代码中的 先后程序来调用过滤器,但是我们可以显式的指定它们的调用顺序:

...
[SimpleMessage(Message="A", Order=2)]
[SimpleMessage(Message="B", Order=1)]
public ActionResult Index() {
Response.Write("Action method is running");
return View();
}
...

这里SimpleMessage是一个action过滤器,通过order我们指定它们的运行顺序: B->OnActionExecuting、A->OnActionExecuting、A->OnActionExecuted、 B->OnActionExecuted。注意A的OnActionExecuted先于B的OnActionExecuted,和 OnActionExecuting正好相反,这是无法改变的。在不指定order时,MVC内部指定为-1。另外如果同类型过滤器指定相同的order 比如都是1,还要根据在哪里应用的过滤器来分先后执行:首先执行的是全局过滤器、然后是控制器类上、最后才是action方法;例外的是 exception过滤器,它的顺序正好与此相反

ASP.NET MVC 4 (三) 过滤器的更多相关文章

  1. ASP.NET MVC 视图(三)

    ASP.NET MVC 视图(三) 前言 上篇对于Razor视图引擎和视图的类型做了大概的讲解,想必大家对视图的本身也有所了解,本篇将利用IoC框架对视图的实现进行依赖注入,在此过程过会让大家更了解的 ...

  2. ASP.NET MVC 路由(三)

    ASP.NET MVC路由(三) 前言 通过前两篇的学习会对路由系统会有一个初步的了解,并且对路由系统中的Url规则有个简单的了解,在大家的脑海中也有个印象了,那么路由系统在ASP.NETMVC中所处 ...

  3. Asp.Net MVC<五>:过滤器

    ControllerActionInvoker在执行过程中除了利用ActionDescriptor完成对目标Action方法本身的执行外,还会执行相关过滤器(Filter).过滤器采用AOP的设计,它 ...

  4. ASP.NET MVC学习之过滤器篇(2)

    下面我们继续之前的ASP.NET MVC学习之过滤器篇(1)进行学习. 3.动作过滤器 顾名思义,这个过滤器就是在动作方法调用前与调用后响应的.我们可以在调用前更改实际调用的动作,也可以在动作调用完成 ...

  5. asp.net MVC之 自定义过滤器(Filter) - shuaixf

    一.系统过滤器使用说明 1.OutputCache过滤器 OutputCache过滤器用于缓存你查询结果,这样可以提高用户体验,也可以减少查询次数.它有以下属性: Duration :缓存的时间, 以 ...

  6. asp.net MVC之 自定义过滤器(Filter)

    一.系统过滤器使用说明 1.OutputCache过滤器 OutputCache过滤器用于缓存你查询结果,这样可以提高用户体验,也可以减少查询次数.它有以下属性: Duration:缓存的时间,以秒为 ...

  7. ASP.NET MVC学习之过滤器篇(1)

    一.前言 继前面四篇ASP.NET MVC的随笔,我们继续向下学习.上一节我们学习了关于控制器的使用,本节我们将要学习如何使用过滤器控制用户访问页面. 二.正文 以下的示例建立在ASP.NET MVC ...

  8. ASP.NET MVC 第三回 Controller与View

    这节我们让ASP.NET MVC真正的跑起来 一.新建Controller 首先我们自己新建一个新的Controller在Controllers上点右键,添加,Controller选项   之后出现一 ...

  9. 笨鸟先飞之ASP.NET MVC系列之过滤器(01过滤器简介)

    过滤器 什么是过滤器? 过滤器(Filter) 主要的作用大致可以理解为把我们的附加逻辑注入到MVC框架的请求处理. 在ASP.NET MVC的请求处理中一种有19个管道事件分别是 BeginRequ ...

随机推荐

  1. dmidecode查看设备硬件信息

    在bash里输入:dmidecode -s system-product-name 或者lshw -class system 在Linux系统环境下(CentOS .4和Ubuntu .04已确认), ...

  2. Eclipse中安装配置Tomcat

    Eclipse(4.4.x及以上)中安装配置Tomcat 以下配置说明全部针对免安装版本 基于tomcat的安装目录和运行目录是可以不同的,本文都会进行说明 首先简单介绍一下tomcat的目录结构,一 ...

  3. repeater留言板[转]

    做了一个网站,其中的在线留言板块是用Repeater来显示留言的,这样可以用少的代码还实现多的功能,但是不知道怎么分页,要是留言过多就会使页面变的很长,能过查看众多网友的经验,知道用PagedData ...

  4. ServerSocket

    在网上找ServerSocket看到的解释

  5. Query Designer:Condition,根据KeyFigure值来过滤数据

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  6. session,ajax 跨域cookie

    什么是Session, 什么是Cookie? Session是由应用服务器维持的一个服务器端的存储空间,用户在连接服务器时,会由服务器生成一个唯一的SessionID,用该SessionID为标识符来 ...

  7. 关于GRUB2

    grub2启动引导 GRUB 2是GNU GRUB(GRand Unified Bootloader)的最新版本.bootloader(引导程序)是计算机开机后(bios自检之后)第一个运行的软件程序 ...

  8. tomcat映射路径的配置方法

    一.默认配置 位置:/conf 文件夹里的server.xml文件 <Host appBase="webapps"> appBase:可以指定绝对目录,也可以指定相对于 ...

  9. matlab 视频转换到图像并保存

    图像处理中像Adas.车辆检测等都需要采用视频文件比较好处理一点,利用帧差法.背景减法.光流法等,那么将视频文件转换到图像文件怎么做呢?话不多说,见代码一目了然: %================= ...

  10. 【转】 如何使用Valgrind memcheck工具进行C/C++的内存泄漏检测

    系统编程中一个重要的方面就是有效地处理与内存相关的问题.你的工作越接近系统,你就需要面对越多的内存问题.有时这些问题非常琐碎,而更多时候它会演变成一个调试内存问题的恶梦.所以,在实践中会用到很多工具来 ...