博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ASP.NET MVC学习系列——MVC过滤器FilterAttribute
阅读量:4502 次
发布时间:2019-06-08

本文共 8225 字,大约阅读时间需要 27 分钟。

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代码如下:

protected virtual bool AuthorizeCore(HttpContextBase httpContext)        {            if (httpContext == null)            {                throw new ArgumentNullException("httpContext");            }             IPrincipal user = httpContext.User;            if (!user.Identity.IsAuthenticated)            {                return false;            }             if (_usersSplit.Length > 0 && !_usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase))            {                return false;            }             if (_rolesSplit.Length > 0 && !_rolesSplit.Any(user.IsInRole))            {                return false;            }             return true;        }

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

public class PermissionFilterAttribute: AuthorizationFilter    {                 protected override bool AuthorizeCore(HttpContextBase httpContext)        {            return true;        }                  protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)        {            filterContext.Result="";                        }    }

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

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

  2.2、ActionFilter过滤器

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

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

 

public class DefaultController : Controller    {        [ActionExecTimeSpan]        public ActionResult DoWork()        {            return View();        }    } public class ActionExecTimeSpanAttribute : ActionFilterAttribute    {        private const string executeActionTimeKey = "ActionExecBegin";         public override void OnActionExecuting(ActionExecutingContext filterContext)        {            base.OnActionExecuting(filterContext);            //记录开始执行时间            filterContext.HttpContext.Items[executeActionTimeKey] = DateTime.Now;        }         public override void OnActionExecuted(ActionExecutedContext filterContext)        {            //计算执行时间,并记录日志            if (filterContext.HttpContext.Items.Contains(executeActionTimeKey))            {                DateTime endTime = DateTime.Now;                DateTime beginTime = Convert.ToDateTime(filterContext.HttpContext.Items[executeActionTimeKey]);                TimeSpan span = endTime - beginTime;                double execTimeSpan = span.TotalMilliseconds;                log.Info(execTimeSpan + "毫秒");            }            //            base.OnActionExecuted(filterContext);        }    }

  2.3、ResultFilter过滤器

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

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

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

public virtual void OnException(ExceptionContext filterContext)        {            if (filterContext == null)            {                throw new ArgumentNullException("filterContext");            }            if (filterContext.IsChildAction)            {                return;            }             // If custom errors are disabled, we need to let the normal ASP.NET exception handler            // execute so that the user can see useful debugging information.            if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)            {                return;            }             Exception exception = filterContext.Exception;             // If this is not an HTTP 500 (for example, if somebody throws an HTTP 404 from an action method),            // ignore it.            if (new HttpException(null, exception).GetHttpCode() != 500)            {                return;            }             if (!ExceptionType.IsInstanceOfType(exception))            {                return;            }             string controllerName = (string)filterContext.RouteData.Values["controller"];            string actionName = (string)filterContext.RouteData.Values["action"];            HandleErrorInfo model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);            filterContext.Result = new ViewResult            {                ViewName = View,                MasterName = Master,                ViewData = new ViewDataDictionary
(model), TempData = filterContext.Controller.TempData }; filterContext.ExceptionHandled = true; filterContext.HttpContext.Response.Clear(); filterContext.HttpContext.Response.StatusCode = 500; // Certain versions of IIS will sometimes use their own error page when // they detect a server error. Setting this property indicates that we // want it to try to render ASP.NET MVC's error page instead. filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; }

 

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

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

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

 
namespace OutputCacheDemo.Controllers{    [OutputCache(Duration = 10)]    public class HomeController : Controller    {        // GET: Home        public string Index()        {            return DateTime.Now.ToString();        }    }}
 

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

public class HomeController : Controller    {        [OutputCache(Duration = 10)]        // GET: Home        public string Index()        {            return DateTime.Now.ToString();        }    }

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

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

public class HomeController : Controller    {        [OutputCache(CacheProfile = "myoutputcache")]        // GET: Home        public string Index()        {            return DateTime.Now.ToString();        }    }

 

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

 

 

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

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

 

转载于:https://www.cnblogs.com/qtiger/p/9640865.html

你可能感兴趣的文章
mybatis整合Spring编码
查看>>
第七章 路由 68 路由-前端路由和后端路由的概念
查看>>
dpkg包管理
查看>>
前端JS利用canvas的drawImage()对图片进行压缩
查看>>
一键切换皮肤的解决思想及iframe嵌套时寻找下级iframe的方法
查看>>
van-dialog 组件调用 报错
查看>>
VC++中的__super::
查看>>
DS1-14
查看>>
c# Mongodb两个字段不相等 MongoDB原生查询
查看>>
排序算法-冒泡排序
查看>>
finally 的作用是什么?
查看>>
嵌入式Linux的调试技术
查看>>
CSS3
查看>>
用友U9 基础使用文件所在目录
查看>>
iOS CALayer 学习(1)
查看>>
jquery 分页控件(一)
查看>>
StackAndQueue(栈与队列)
查看>>
URLOS安装、升级、卸载
查看>>
最新dedecms网页游戏开服表发号网站源码模板
查看>>
在win7下配置sql2005允许远程访问
查看>>