• MVC之Filter


    • Filter就是特性,特性是定义在类或者属性上的,另外提一下,MVC的Filter是在控制器实例化之后反射获取的,比一般HttpModule扩展的方法要靠后执行且能具体到类以及其方法;
    • Filter 接口及其默认实现类,4种接口,3种实现类,下面将通过继承实现类,复写响应的方法实现自定义MVC过滤器
    Filter类型接口MVC的默认实现Description
    AuthorizationIAuthorizationFilterAuthorizeAttribute最先执行,在其他类型的filter和action方法前执行
    ActionIActionFilterActionFilterAttribute在action方法执行前和执行后执行
    ResultIResultFilterActionFilterAttribute在result执行前和执行后执行
    ExceptionIExceptionFilterHandleErrorAttribute在抛出异常时执行,(异常发生在action/result/filter)
    1. AuthorizeAttribute权限过滤器

      1. 新增一个自定义类,继承自AuthorizeAttribute类,重写OnAuthorization()方法,注意细节:
        • 全局注册:在Global.asax里的Application_Start()方法里的过滤器注册里注册,即在FilterConfig.RegisterGlobalFilters()里新增一行代码:filters.Add(new CustomAuthorizeAttribute("~/Login/index"));
        • 允许自定义登录页的URL,即没有登录的请求,自动跳转到指定登录页去,并设有登录页URL默认值;
        • 首先判断有没有匿名特性,要判断方法和控制器上是否有filterContext.ActionDescriptor.IsDefined(typeof(AllowHtmlAttribute), true) || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowHtmlAttribute), true),如果允许匿名则直接return
        • 如果登录失败,除了跳转到登录页,还要考虑是否是ajax请求,如果是则:if(httpContext.Request.IsAjaxRequest())并返回filterContext.Result = new JsonResult(){data={}},否则跳转页面(return view()return Redirect()return RedirectToAction()
        • 如果登录失败,记录初始请求的URL在Session里,然后再登录页面后台代码里,如果登录成功,判断Seesion里是否有指定名称的URL,如果有则跳转到这个URL里,否则跳转到首页;
        • 登录成功,直接return;,只有验证失败,才需要给httpContext.result赋值,成功不用赋值(null),MVC自动会进入action里;
            public override void OnAuthorization(AuthorizationContext filterContext)
            {
                //匿名控制器或方法,直接return
                bool re = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true) || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true);
                if (re)
                {
                    return;
                }
                var session = filterContext.HttpContext.Session["CurrentUser"];
                if (session != null)
                {
                    //登录验证成功,直接return,类似匿名特性处理
                    return;
                }
                else
                {
                    //验证失败,重定向到登录页
                    filterContext.HttpContext.Session["PreUrl"] = filterContext.HttpContext.Request.Url;
                    filterContext.Result = new RedirectResult(_LoginUrl);
                }
                //base.OnAuthorization(filterContext);
            }
    
    1. HandleErrorAttribute异常过滤器

    • 与权限过滤器类似,先新增一个类,继承自HandleErrorAttribute,重写OnExceptionHandle()方法;
    • 全局注册,也是在FilterConfig.RegisterGlobalFilters()新增一行:filters.Add(new MyHandleErrorAttribute());
    • 一般记录日志,错误信息在这个属性里:filterContext.Exception,然后将exceptionHandled设置为true,表示已处理了这个异常,同理处理这个异常前,也要判断这个属性exceptionHandled,为false才表示还未处理此异常;
    • 过滤器filter的生效是在控制器controller实例化且方法调用后才生效的,所以控制器实例化的错误不能被捕获到,同理,URL错误也不会被捕获;
    • 还有一种可以捕获MVC所有异常的方法,在Global.asax里新增protected void Application_Error(object sender, EventArgs e){ Exception error = Server.GetLastError(); //日志记录; Server.ClearError();},但此异常捕获,比较粗犷;
        public override void OnException(ExceptionContext filterContext)
            {
                //如果异常没有处理过
                if (!filterContext.ExceptionHandled)
                {
                    //log4net写日志
                    LogHelper.WriteLog($"{filterContext.HttpContext.Request.Url.ToString()}", filterContext.Exception);
                    //ajax请求,返回json结果,由前端js处理
                    if (filterContext.HttpContext.Request.IsAjaxRequest())
                    {
                        filterContext.Result = new JsonResult()
                        {
                            Data = new AjaxResult()
                            {
                                Result = DoResult.Failed,
                                PromptMsg = filterContext.Exception.Message,
                            }
                        };
                    }
                    else
                    {
                        //异常,重定向到一个异常页去
                        filterContext.Result = new RedirectResult("~/common/error");
                    }
                    filterContext.ExceptionHandled = true;
                }
                //base.OnException(filterContext);
            }
    
    1. ActionFilterAttribute方法过滤器

    • ActionFilterAttribute类既实现了IactionFilter接口,也实现IResultFilter接口。
    • 与之前的2个过滤器类似,新增类,继承类;
    • 不过里面有4个方法,分别时Action执行前,Action执行后,Result前,Result后;
    • 也可以全局注册或只在某个控制器或某个方法上,比如压缩响应结果;
    //对响应结果压缩
            public override void OnActionExecuting(ActionExecutingContext filterContext)
          {
              //Accept-Encoding: gzip, deflate, br
              var acceptEncoding = filterContext.HttpContext.Request.Headers["Accept-Encoding"];
              if (string.IsNullOrEmpty(acceptEncoding))
              {
                  return;
              }
              if (acceptEncoding.IndexOf("gzip", StringComparison.OrdinalIgnoreCase) >= 0)
              {
                  filterContext.HttpContext.Response.Filter = new GZipStream(filterContext.HttpContext.Response.Filter, CompressionLevel.Optimal);
                  filterContext.HttpContext.Response.Headers.Add("Content-encoding", "gzip");
    
              }
              else if (acceptEncoding.IndexOf("deflate", StringComparison.OrdinalIgnoreCase) >= 0)
              {
                  filterContext.HttpContext.Response.Filter = new DeflateStream(filterContext.HttpContext.Response.Filter, CompressionLevel.Fastest);
                  filterContext.HttpContext.Response.Headers.Add("Content-encoding", "deflate");
              }
    
              //base.OnActionExecuting(filterContext);
          }
    
    //全局注册过滤器,所有控制器或方法均生效
     public static void RegisterGlobalFilters(GlobalFilterCollection filters)
           {
               //异常
               filters.Add(new MyHandleErrorAttribute());
               //权限验证
               filters.Add(new MyAuthorizeAttribute());
               //压缩
               filters.Add(new MyCompressAttribute());
    
           }
    

    AOP与MVC的Filter

    • MVC的Filter就是AOP的实现,MVC的Filter最细只能到Action级别,而第三方的AOP可以细到Action内部的方法,只要这个方法实现了指定的接口;
  • 相关阅读:
    mbedtls安装与入门【转】
    SpringAop代理对象调用过程(八)
    SpringAOP理解-代理对象创建(七)
    NIO与零拷贝
    NIO实现群聊系统
    SpringAOP概述(六)
    NIO简介以及三大组件(BufferChannelSelector)基本使用
    BIO基本介绍以及使用
    Netty简介
    Spring循环依赖解决(五)
  • 原文地址:https://www.cnblogs.com/zoulei0718/p/14315572.html
Copyright © 2020-2023  润新知