1、概括

  MVC提供的几种过滤器其实也是一种特性(Attribute),MVC支持的过滤器类型有四种,分别是:AuthorizationFilter(授权),ActionFilter(行为),ResultFilter(结果)和ExceptionFilter(异常),他们分别对应了四个筛选器接口IAuthorizationFilter、IActionFilter、IResultFilter和IExceptionFilter。这四种筛选器都有派生于一个公共的类FilterAttribute,该类指定了筛选器的执行顺序Order和是否允许多个应用AllowedMultiple。这四种筛选器默认的执行顺序为最先进行授权筛选,最后进行异常处理,中间则是ActionFilter和ResultedFilter。官网对FilterAttribute层次结构的介绍图如下

2、MVC四大过滤器介绍

  2.1、AuthorizeFilter筛选器

  AuthorizeAttribute为最终授权过滤器的实现者,它实现了IAuthorizationFilter接口和FilterAttribute抽象类,接口中的OnAuthorization(AuthorizationContext filterContext)方法是最终验证授权的逻辑(其中AuthorizationContext是继承了ControllerContext类),AuthorizeCore方法是最终OnAuthorization()方法调用的最终逻辑。

  • bool AuthorizeCore(HttpContextBase httpContext):授权验证的逻辑处理,返回true则是通过授权,返回false则不是。若验证不通过时,OnAuthorization方法内部会调用HandleUnauthorizedRequest
  • void HandleUnauthorizedRequest(AuthorizationContext filterContext):这个方法是处理授权失败的事情。

AuthorizeCore代码如下:

  1. protected virtual bool AuthorizeCore(HttpContextBase httpContext)
  2. {
  3. if (httpContext == null)
  4. {
  5. throw new ArgumentNullException("httpContext");
  6. }
  7.  
  8. IPrincipal user = httpContext.User;
  9. if (!user.Identity.IsAuthenticated)
  10. {
  11. return false;
  12. }
  13.  
  14. if (_usersSplit.Length > && !_usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase))
  15. {
  16. return false;
  17. }
  18.  
  19. if (_rolesSplit.Length > && !_rolesSplit.Any(user.IsInRole))
  20. {
  21. return false;
  22. }
  23.  
  24. return true;
  25. }

我们不一定要用MVC默认的Authorize授权验证规则,规则可以自己来定,自定义授权过滤器继承IAuthorizeAttribute和FilterAttribute,由于OnAthurization()、AuthorizeCore()和HandleUnauthorizedRequest()方法都是虚方法,这些方法是可以重写的,这样就可以自定义自己的验证规则和验证失败时的处理逻辑了。示例代码如下

  1. public class PermissionFilterAttribute: AuthorizationFilter
  2. {
  3.  
  4. protected override bool AuthorizeCore(HttpContextBase httpContext)
  5. {
  6. return true;
  7. }
  8.  
  9. protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
  10. {
  11. filterContext.Result="";
  12.  
  13. }
  14. }

授权过滤器的使用方式一如下:

  1. [PermissionFilterAttribute]
    public ActionResult index()
    {
      return View();
    }

  2.2、ActionFilter过滤器

  ActionFilter过滤器是在Action方法执行前后会触发,主要用于在Action执行前后处理一些相应的逻辑。ActionFilter的过滤器都继承于ActionFilterAttribute抽象类,而它实现了IActionFilter、IResultFilter和FilterAttribute类,结构如下

因此自定义ActionFilter过滤器只要继承ActionFilterAttribute,实现其中的方法即可。我们来举一个简单的例子,获取Action方法的执行时长,代码如下

  1. public class DefaultController : Controller
  2. {
  3. [ActionExecTimeSpan]
  4. public ActionResult DoWork()
  5. {
  6. return View();
  7. }
  8. }
  9.  
  10. public class ActionExecTimeSpanAttribute : ActionFilterAttribute
  11. {
  12. private const string executeActionTimeKey = "ActionExecBegin";
  13.  
  14. public override void OnActionExecuting(ActionExecutingContext filterContext)
  15. {
  16. base.OnActionExecuting(filterContext);
  17. //记录开始执行时间
  18. filterContext.HttpContext.Items[executeActionTimeKey] = DateTime.Now;
  19. }
  20.  
  21. public override void OnActionExecuted(ActionExecutedContext filterContext)
  22. {
  23. //计算执行时间,并记录日志
  24. if (filterContext.HttpContext.Items.Contains(executeActionTimeKey))
  25. {
  26. DateTime endTime = DateTime.Now;
  27. DateTime beginTime = Convert.ToDateTime(filterContext.HttpContext.Items[executeActionTimeKey]);
  28. TimeSpan span = endTime - beginTime;
  29. double execTimeSpan = span.TotalMilliseconds;
  30. log.Info(execTimeSpan + "毫秒");
  31. }
  32. //
  33. base.OnActionExecuted(filterContext);
  34. }
  35. }

  2.3、ResultFilter过滤器

  ResultFilter过滤器是对Action方法返回的Result结果进行执行时触发的。它也分执行前和执行后两个段执行,所有的ResultFilter都实现了IResultFilter接口和FilterAttribute类,看一下接口定义

  1. public interface IResultFilter
  2. {
  3. void OnResultExecuting(ResultExecutingContext filterContext);
  4.  
  5. void OnResultExecuted(ResultExecutedContext filterContext);
  6. }
  1. 其中OnResultExecutingOnResultExecuted方法分别是在Result执行前、后(页面展示内容生成前、后)触发。使用ResultFilter筛选器最典型的应用就是页面静态化。
      
  1. 2.4ExceptionFilter过滤器(详细介绍https://www.cnblogs.com/qtiger/p/10824562.html
      
    该过滤器是在系统出现异常时触发,可以对抛出的异常进行处理。所有的ExceptionFilter筛选器都是实现自IExceptionFilter接口 
  1. public interface IExceptionFilter
  2. {
  3. void OnException(ExceptionContext filterContext);
  4. }

实现OnException方法来实现对异常的自定义处理,MVC4中实现了默认的异常处理机制,源码如下

  1. public virtual void OnException(ExceptionContext filterContext)
  2. {
  3. if (filterContext == null)
  4. {
  5. throw new ArgumentNullException("filterContext");
  6. }
  7. if (filterContext.IsChildAction)
  8. {
  9. return;
  10. }
  11.  
  12. // If custom errors are disabled, we need to let the normal ASP.NET exception handler
  13. // execute so that the user can see useful debugging information.
  14. if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
  15. {
  16. return;
  17. }
  18.  
  19. Exception exception = filterContext.Exception;
  20.  
  21. // If this is not an HTTP 500 (for example, if somebody throws an HTTP 404 from an action method),
  22. // ignore it.
  23. if (new HttpException(null, exception).GetHttpCode() != )
  24. {
  25. return;
  26. }
  27.  
  28. if (!ExceptionType.IsInstanceOfType(exception))
  29. {
  30. return;
  31. }
  32.  
  33. string controllerName = (string)filterContext.RouteData.Values["controller"];
  34. string actionName = (string)filterContext.RouteData.Values["action"];
  35. HandleErrorInfo model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
  36. filterContext.Result = new ViewResult
  37. {
  38. ViewName = View,
  39. MasterName = Master,
  40. ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
  41. TempData = filterContext.Controller.TempData
  42. };
  43. filterContext.ExceptionHandled = true;
  44. filterContext.HttpContext.Response.Clear();
  45. filterContext.HttpContext.Response.StatusCode = ;
  46.  
  47. // Certain versions of IIS will sometimes use their own error page when
  48. // they detect a server error. Setting this property indicates that we
  49. // want it to try to render ASP.NET MVC's error page instead.
  50. filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
  51. }

  Application_Start中将HandleErrorAttribute添加到全局过滤器GlobalFilterCollection中,系统即会对异常进行对应的处理。

  1. 3、其他的过滤器
      
    3.1OutputCache过滤器
      表示一个特性,该特性用于标记将缓存其输出的操作方法。当用户访问页面时,整个页面将会被服务器保存在内存中,这样就对页面进行了缓存。当用户再次访问该页,
    页面不会再次执行数据操作,页面首先会检查服务器中是否存在缓存,如果缓存存在,则直接从缓存中获取页面信息,如果页面不存在,则创建缓存。OutputCache的代码定义片段如下:
  1. [AttributeUsageAttribute(AttributeTargets.Class|AttributeTargets.Method, Inherited = true,
  2. AllowMultiple = false)]
  3. public class OutputCacheAttribute : ActionFilterAttribute,
  4. IExceptionFilter

从上面的代码中可以看到该特性可以应用在类,方法上面。在mvc中,就可以直接在控制器上面或者控制器中的Action上面直接使用,做到细粒度的对缓存的控制。

  1.  
  1. namespace OutputCacheDemo.Controllers
  2. {
  3. [OutputCache(Duration = )]
  4. public class HomeController : Controller
  5. {
  6. // GET: Home
  7. public string Index()
  8. {
  9. return DateTime.Now.ToString();
  10. }
  11. }
  12. }
  1.  

上面的代码是将OutputCache特性标记在了控制器类上,以达到该控制器上所有的Action都将应用该特性,过期时间设置为10s。10s后缓存过期,再访问就会更新时间。OutputCache特性也可以设置在Action方法上面,以达到更细粒度的控制缓存,代码如下:

  1. public class HomeController : Controller
  2. {
  3. [OutputCache(Duration = )]
  4. // GET: Home
  5. public string Index()
  6. {
  7. return DateTime.Now.ToString();
  8. }
  9. }

此时,只有Index的页面进行了缓存。如果多个控制器或者Action使用相同的缓存配置,可以在配置文件中进行统一配置。

  1. <system.web>
  2. <caching>
  3. <outputCacheSettings>
  4. <outputCacheProfiles >
  5. <add name='myoutputcache' duration=''/>
  6. </outputCacheProfiles>
  7. </outputCacheSettings>
  8. </caching>
  9. <compilation debug="true" targetFramework="4.5"/>
  10. <httpRuntime targetFramework="4.5"/>
  11. </system.web>

应用名称为myoutputcache的缓存代码如下:

  1. public class HomeController : Controller
  2. {
  3. [OutputCache(CacheProfile = "myoutputcache")]
  4. // GET: Home
  5. public string Index()
  6. {
  7. return DateTime.Now.ToString();
  8. }
  9. }

注意:当控制器和Action同时使用了OutputCache特性时,以Action为主。

参考资料:https://www.cnblogs.com/wolf-sun/p/6219245.html

    https://blog.csdn.net/zyh_1988/article/details/52234111

  1.  

ASP.NET MVC学习系列(4)——MVC过滤器FilterAttribute的更多相关文章

  1. ASP.NET MVC学习系列(二)-WebAPI请求

    继续接着上文 ASP.NET MVC学习系列(一)-WebAPI初探 来看看对于一般前台页面发起的get和post请求,我们在Web API中要如何来处理. 这里我使用Jquery 来发起异步请求实现 ...

  2. ASP.NET MVC学习系列(二)-WebAPI请求(转)

    转自:http://www.cnblogs.com/babycool/p/3922738.html 继续接着上文 ASP.NET MVC学习系列(一)-WebAPI初探 来看看对于一般前台页面发起的g ...

  3. [转]ASP.NET MVC学习系列(二)-WebAPI请求 传参

    [转]ASP.NET MVC学习系列(二)-WebAPI请求 传参 本文转自:http://www.cnblogs.com/babycool/p/3922738.html ASP.NET MVC学习系 ...

  4. ASP.NET MVC学习系列(二)-WebAPI请求 转载https://www.cnblogs.com/babycool/p/3922738.html

    继续接着上文 ASP.NET MVC学习系列(一)-WebAPI初探 来看看对于一般前台页面发起的get和post请求,我们在Web API中要如何来处理. 这里我使用Jquery 来发起异步请求实现 ...

  5. MVC学习系列4--@helper辅助方法和用户自定义HTML方法

    在HTML Helper,帮助类的帮助下,我们可以动态的创建HTML控件.HTML帮助类是在视图中,用来呈现HTML内容的.HTML帮助类是一个方法,它返回的是string类型的值. HTML帮助类, ...

  6. MVC学习系列——ModelBinder扩展

    在MVC系统中,我们接受数据,运用的是ModelBinder 的技术. MVC学习系列——ActionResult扩展在这个系列中,我们自定义了XmlResult的返回结果. 那么是不是意味着能POS ...

  7. MVC学习系列——记一次失败面试后,感想。

    在此写博客之际,热烈庆祝母校苏州科技学院,正式改名为苏州科技大学. 一晃眼,从自己投身IT行业已经两年有余,期间经历了结婚.买房等人生大事,非常感谢我的老婆,谢谢她这么爱我,嫁给我这个码农,呵呵... ...

  8. MVC学习一:MVC简单流程

    MVC学习一:MVC初次接触 1.MVC简单流程 1.1.服务器接收客户端请求后,解析URL(根据 路由表里配置的URL来分析 类名(控制器名)和方法名)根据请求的类名,创建对应的控制器类对象,并调用 ...

  9. Asp.net MVC 学习系列(一)序

    题外话 公司本月开始提供早餐服务,2块天一餐,包括粥,两个包(听说是利口福供应的),一个鸡蛋.良心企业.公司原本有一个内部订餐系统,用Delphi开发的,开发的人早就走光了,也没有留下什么文档,现在项 ...

随机推荐

  1. 初学Java Web(6)——JSP学习总结

    为什么要学习 JSP Servlet 的短板: Servlet 的出现,是为了解决动态输出网页的问题. 虽然这样做目的能达到,但是存在一些缺陷: 在 Servlet 输出网页片段非常恶心 (可读性差, ...

  2. RabbitMQ消息队列(七)-通过fanout模式将消息推送到多个Queue中(.Net Core版)

    前面第六章我们使用的是direct直连模式来进行消息投递和分发.本章将介绍如何使用fanout模式将消息推送到多个队列. 有时我们会遇到这样的情况,多个功能模块都希望得到完整的消息数据.例如一个log ...

  3. NTP服务器搭建

    NTP服务器搭建 :http://www.jbxue.com/LINUXjishu/22352.html 客户端配置: vim /etc/ntp.conf #server 0.centos.pool. ...

  4. Spring Cloud Alibaba基础教程:使用Nacos作为配置中心

    通过本教程的前两篇: <Spring Cloud Alibaba基础教程:使用Nacos实现服务注册与发现> <Spring Cloud Alibaba基础教程:支持的几种服务消费方 ...

  5. 委托初级篇——lambda表达式的推导

    public delegate void ConsoleWriteStr(string name,DateTime now); public delegate int DelegateAdd(int ...

  6. [PHP] strpos stripos strrpos strripos的区别

    stripos — 查找字符串首次出现的位置(不区分大小写),应使用 === 运算符来测试此函数的返回值 strpos 左边开始字符出现的第一个位置,区分大小写stripos 和上面一样,不区分大小写 ...

  7. JAVA_接口_默认方法&静态方法

    1.小结(注意): 1.接口中无法定义成员变量,但是可以定义常量,其值不可以改变,默认使用public static final修饰 2.接口中,没有构造方法,不能创建对象 3.接口中,没有静态代码块 ...

  8. 记一次servlet项目启动

    前言 tomcat 和 jetty 都属于 web 容器. mac安装tomcat brew install tomcat 安装之后,输入 catalina -h,可以看到各种命令,如run.star ...

  9. ajaxFileUpload onchang上传文件插件第二次失效刷新一次才能再次调用触发change事件

    关于用ajaxfileupload时,遇到一个要刷新一次页面才能再次上传, ajaxFileUpload 用onchang上传只能上传一次 第二次就失效了 我找这个问题找了很长时间 ajaxFileU ...

  10. Linux下Jenkins服务器搭建

    系统环境 操作系统:CentOS6.9 java jdk:java 8 Jenkins版本:jenkins-2.78-1.1.noarch.rpm 关闭防火墙 注意:如果是基于msbuild构建.ne ...