zoukankan      html  css  js  c++  java
  • MVC四大筛选器—ActionFilter&ResultedFilter

    AuthorizeFilter筛选器

    在Action的执行中包括两个重要的部分,一个是Action方法本身逻辑代码的执行,第二个就是Action方法的筛选器的执行。

    MVC4中筛选器都是以AOP(面向方面编程)的方式来设计的,通过对Action方法上标注相应的Attribute标签来实现。MVC4提供了四种筛选器,分别为:AuthorizationFilter、ActionFilter、ExceptionFilter和ResultFilter,他们分别对应了四个筛选器接口IAuthorizationFilter、IActionFilter、IExceptionFilter和IResultFilter。

    这四种筛选器都有派生于一个公共的类FilterAttribute,该类指定了筛选器的执行顺序Order和是否允许多个应用AllowedMultiple。这四种筛选器默认的执行顺序为最先进行授权筛选,最后进行异常处理,中间则是ActionFilter和ResultedFilter。

    下面是抽象类FilterAttribute的类图

     

    下面我们来具体列举一下各个筛选器的作用和实现

    从字面上我们就能看出这是对Controller或Action方法授权的筛选器,即在Controller或Action方法执行前,首先会先执行该筛选器,若通过,才会继续执行。下面是此筛选器的简单类图

     

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

    [csharp] view plain copy
     
    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 > 0 && !_usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase))  
    15.             {  
    16.                 return false;  
    17.             }  
    18.   
    19.             if (_rolesSplit.Length > 0 && !_rolesSplit.Any(user.IsInRole))  
    20.             {  
    21.                 return false;  
    22.             }  
    23.   
    24.             return true;  
    25.         }  

    AuthorizeCore方法是最终OnAuthorization()方法调用的最终逻辑,从代码可以看出,当同时指定了users和roles时,两者只有同时满足条件时才可以验证授权通过。如

    [csharp] view plain copy
     
    1. [Authorize(Users="zhangsan", Roles="Admin")]  
    2.        public ActionResult ActionMethod()  
    3.        {  
    4.        }  

    则只有用户zhangsan,且用户属于Admin角色时才能验证授权通过。

    若验证不通过时,OnAuthorization方法内部会调用HandleUnauthorizedRequest

    虚方法进行处理,代码如下:

    [csharp] view plain copy
     
    1. protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext)  
    2.         {  
    3.             // Returns HTTP 401 - see comment in HttpUnauthorizedResult.cs.  
    4.             filterContext.Result = new HttpUnauthorizedResult();  
    5.         }  

    该方法设置了参数上下文中ActionResult的值,用于供View展示。

    我们可以自定义Authorize筛选器,由于OnAthurization()、AuthorizeCore()和HandleUnauthorizedRequest()方法都是虚方法,我们自定义的Authorize筛选器只需要继承AuthorizeAttribute类,重写以上三种方法,这样就可以自定义自己的验证规则和验证失败时的处理逻辑了。

    IAuthorizationFilter还有其他类型的实现类,如RequireHttpsAttribute、ValidateInputAttribute都是实现了OnAuthorization()方法,来完成各自筛选器处理的。

    ExceptionFilter过滤器


    该筛选器是在系统出现异常时触发,可以对抛出的异常进行处理。所有的ExceptionFilter筛选器都是实现自IExceptionFilter接口  

    [csharp] view plain copy
     
    1. public interface IExceptionFilter  
    2.     {  
    3.         void OnException(ExceptionContext filterContext);  
    4.     }  

    实现OnException方法来实现对异常的自定义处理

    MVC4中实现了默认的异常处理机制,源码如下 

    [csharp] view plain copy
     
    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() != 500)  
    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 = 500;  
    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中,系统即会对异常进行对应的处理。
    我们现在实现一个自定义的异常处理筛选器,在处理完后记录异常信息至日志文件中  
    [csharp] view plain copy
     
    1. public class MyExceptionHandleAttribute : HandleErrorAttribute  
    2.     {  
    3.         public MyExceptionHandleAttribute()  
    4.             : base()  
    5.         {  
    6.         }  
    7.   
    8.         public void OnException(ExceptionContext filterContext)  
    9.         {  
    10.             base.OnException(filterContext);  
    11.             //记录日志  
    12.             log.Info(filterContext.Exception);  
    13.         }  
    14.     }  

    在GlobalFilterCollection添加MyExceptionHandleAttribute 即可使用自定义的异常筛选器来处理

    ActionFilter筛选器

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

     

    因此自定义ActionFilter筛选器只要继承ActionFilterAttribute,实现其中的方法即可。

    我们来举一个简单的例子,获取Action方法的执行时长,代码如下

    [csharp] view plain copy
     
    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.     }  

    ResultFilter筛选器

    ResultFilter筛选器是对Action方法返回的Result结果进行执行时触发的。它也分执行前和执行后两个段执行

    所有的ResultFilter都实现了IResultFilter接口和FilterAttribute类,看一下接口定义

    [csharp] view plain copy
     
    1. public interface IResultFilter  
    2.    {  
    3.        void OnResultExecuting(ResultExecutingContext filterContext);  
    4.   
    5.        void OnResultExecuted(ResultExecutedContext filterContext);  
    6.    }  
    其中OnResultExecuting和OnResultExecuted方法分别是在Result执行前、后(页面展示内容生成前、后)触发。
    使用ResultFilter筛选器最典型的应用就是页面静态化,我们以后在其他文章中在对此进行详细讲解
    
    
    学习什么时候都不晚,从现在起我们一起
  • 相关阅读:
    移动端解决fixed和input弹出虚拟键盘时样式错位
    JS的面向对象
    js计算两个时间范围间的间隔秒数
    使用js过滤字符串前后的空格
    C#时间格式-摘自http://www.cnblogs.com/xiaogongzhu/p/3825600.html
    [dp/贪心]435. 无重叠区间-----经典问题
    【dp】Leetcode面试题 17.16. 按摩师
    [dp]Leetcode.376.摆动序列
    Leetcode 945 使数组唯一的最小增量
    LeetCode 365.水壶问题
  • 原文地址:https://www.cnblogs.com/jjg0519/p/8759221.html
Copyright © 2011-2022 走看看