• .Net Filter原理(使用特性 Attribute)这是一个AOP编程


    一、自定义权限认证特性 CheckLoginAttribute

      基于.net core mvc的验证Session登陆状态

    1.新建一个.net core mvc项目

    2.在Models文件夹下面添加一个类MyAttribute,专门用来保存我们定义的特性

      在这里我只写了CheckLoginAttribute用来验证登陆情况

    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.Filters;
    using System;
    namespace AttributeStudy.Models
    {
        public class MyAttribute
        {
    
        }
        public class CheckLoginAttribute : Attribute,IActionFilter
        {
            public void OnActionExecuted(ActionExecutedContext context)//方法执行后执行
            {
    
            }
    
            public void OnActionExecuting(ActionExecutingContext context)//方法执行前执行
            {
                if(context.HttpContext.Session.GetString("LoginName")==null)
                {
                    context.Result = new RedirectResult("Contact");//如果不存在这个Session则表示登陆不成功,跳到Contact页面
                }
                else
                {
              //否则,不做操作。
                }
            }
        }
    
    }

      因为这里不是controller,所以,我们要得使用session得用注入的context来调用

      而且,在.Net core使用Sesion还得在Startup添加配置

    ConfigureServices下面添加          services.AddSession();
    Configure下面添加                  app.UseSession();

       HomeController如下:

    using AttributeStudy.Models;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using System.Diagnostics;
    
    namespace AttributeStudy.Controllers
    {
        public class HomeController : Controller
        {
            public IActionResult Index()
            {
                return View();
            }
            public void SetSession(int i)//做测试用,添加LogonName这个Session
            {
                HttpContext.Session.SetString("LoginName", "123456");
            }
            public void RemoveSession(int i,int j)//做测试用,删除LogonName这个Session
            {
                HttpContext.Session.Remove("LoginName");
            }
            [CheckLogin]
            public IActionResult About()
            {
                ViewData["Message"] = "Your application description page.";
                return View();
            }
    
            public IActionResult Contact()
            {
                ViewData["Message"] = "Your contact page.";
                return View();
            }
            public IActionResult Error()
            {
                return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
            }
        }
    }

      这样我们检测登陆特性已经可以演示了,启动后,在网页点击About,会先检执行CheckLoginAttribute的OnActionExecuting做登陆验证。

    二、自定义权限认证特性 CustomAuthorizeAttribute

      基于.net mvc 的验证Session登陆状态

    1.新建一个.net mvc项目

      添加控制器Login、并在控制器index右键添加index视图

        public class LoginController : Controller
        {
            // GET: Login
            public ActionResult Index()
            {
                return View();
            }
    
            public string Login()
            {
                HttpContext.Session["StudyAOPSession"] = "kxy&123";
                return "登录成功";
            }
    
            public string Out()
            {
                HttpContext.Session["StudyAOPSession"] = null;
                return "已退出";
            }
        }

      index视图

    @{
        ViewBag.Title = "Index";
    }
    
    <h2>请登录!</h2>
    @Html.ActionLink("登录", "Login", "Login")
    @Html.ActionLink("退出", "Out", "Login")

    2.新建文件夹CustomAttribute,并添加类 CustomAuthorizeAttribute

        public class CustomAuthorizeAttribute: AuthorizeAttribute
        {
         // 加上这个特性 会先执行这个函数
    public override void OnAuthorization(AuthorizationContext filterContext) { var StudyAOPSession = filterContext.HttpContext.Session["StudyAOPSession"]; // 判断登录Session是否存在、账号密码是否正确(这里只是模拟一下) if (StudyAOPSession == null || !StudyAOPSession.ToString().Equals("kxy&123")) { filterContext.Result = new ViewResult() { ViewName = "~/Views/Login/index.cshtml" }; } } }

      这样我们就新建好了一个用来验证登陆的特性

      加特性的三个地方

      1、Action:方法注册、指定某个方法

      2、Controller:控制器注册、指定控制器下面的所有方法

      3、FilterConfig:全局注册,在App_Start 里面的 FilterConfig

        public class FilterConfig
        {
            public static void RegisterGlobalFilters(GlobalFilterCollection filters)
            {
                filters.Add(new HandleErrorAttribute());
                filters.Add(new CustomAuthorizeAttribute());// 我们加的特性
            }
        }

     3.允许匿名访问  AllowAnonymous

      AllowAnonymous不是添加了就有效,需要在自定义特性判断是否有添加AllowAnonymous,已经添加了就是允许匿名,直接return,不做筛选操作

      修改类:CustomAuthorizeAttribute

        public class CustomAuthorizeAttribute : AuthorizeAttribute
        {
            public override void OnAuthorization(AuthorizationContext filterContext)
            {
                if (filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true))
                    return;//判断控制器是否允许匿名
                if (filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true))
                    return;//判断Action是否允许匿名
                var StudyAOPSession = filterContext.HttpContext.Session["StudyAOPSession"];
                // 判断登录Session是否存在、账号密码是否正确(这里只是模拟一下)
                if (StudyAOPSession == null || !StudyAOPSession.ToString().Equals("kxy&123"))
                {
                    filterContext.Result = new ViewResult()
                    {
                        ViewName = "~/Views/Login/index.cshtml"
                    };
                }
            }
        }

      AllowAnonymous特性可以注册在Controller或者Action上面

    三、自定义捕捉异常特性 CustomHandleErrorAttribute

        public class CustomHandleErrorAttribute : HandleErrorAttribute
        {
            public override void OnException(ExceptionContext filterContext)
            {
                if (filterContext.ExceptionHandled)
                    return;//异常已被处理,这里不再处理
                filterContext.Result = new ViewResult()
                {
                    //捕捉到未被处理的异常(也就是没有catch掉的异常),转到错误页,显示错误信息
                    ViewName = "~/Views/Shared/Error.cshtml",
                    ViewData = new ViewDataDictionary<string>(filterContext.Exception.Message)
                };
                filterContext.ExceptionHandled = true;//标记已处理
            }
        }

      Error页如下

    <!DOCTYPE html>
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <meta name="viewport" content="width=device-width" />
        <title>错误</title>
    </head>
    <body>
        <hgroup>
            <h1>错误。</h1>
            <h2>处理你的请求时出错。</h2>
            <h3>@Model</h3>
        </hgroup>
    </body>
    </html>

      CustomHandleErrorAttribute 可以进行方法、控制器、全局注册

      一般而言,捕捉异常会用全局注册

        public class FilterConfig
        {
            public static void RegisterGlobalFilters(GlobalFilterCollection filters)
            {
                //filters.Add(new HandleErrorAttribute());//这是自带的异常捕捉特性,现在换成我们自己的
                filters.Add(new CustomHandleErrorAttribute());
            }
        }

      软谋教育举例的七大异常:

        

      可以看出5、6、7 这三个场景并不能被捕捉到,还是会出现异常黄页

      可以通过在Global.asax.cs 添加如下函数进行异常捕捉

            /// <summary>
            /// 保底全局异常处理,任何最终没有被处理的异常都会来这里
            /// 但是获取的信息比较粗略,所以是作为补充
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            protected void Application_Error(object sender,EventArgs e)
            {
                var error = Server.GetLastError();
                Server.ClearError();// 将错误清除掉
                Response.Write(error.Message);
            }

      注意,函数名和参数必须是这样  不能改

      PS:异常捕捉特性可以捕捉  权限认证特性和方法过滤特性里面发送的异常

    四、自定义方法过滤特性 CustomActionFilterAttribute

      可用于页面压缩

     1.特性代码演示

        /// <summary>
        /// 自定义Action过滤特性
        /// </summary>
        public class CustomActionFilterAttribute : ActionFilterAttribute
        {
            /// <summary>
            /// 动作执行前
            /// </summary>
            /// <param name="filterContext"></param>
            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                filterContext.HttpContext.Response.Write("动作执行前<br />");
            }
            /// <summary>
            /// 动作执行后
            /// </summary>
            /// <param name="filterContext"></param>
            public override void OnActionExecuted(ActionExecutedContext filterContext)
            {
                filterContext.HttpContext.Response.Write("动作执行后<br />");
            }
            /// <summary>
            /// 视图加载前
            /// </summary>
            /// <param name="filterContext"></param>
            public override void OnResultExecuting(ResultExecutingContext filterContext)
            {
                filterContext.HttpContext.Response.Write("视图加载前<br />");
            }
            /// <summary>
            /// 视图加载后
            /// </summary>
            /// <param name="filterContext"></param>
            public override void OnResultExecuted(ResultExecutedContext filterContext)
            {
                filterContext.HttpContext.Response.Write("视图加载后<br />");
            }
        }

      这个特性分别是网页面添加一句话,在Home的About方法注册一下这个特性

            [CustomActionFilter]
            public ActionResult About()
            {
                ViewBag.Message = "Your application description page.";
                return View();
            }

      页面如下:

      从这里我们可以看出,在Action执行前后四个特性函数的执行顺序

    2.使用函数 OnActionExecuting 进行页面压缩

      我们先看一下没有压缩的About网页的 请求头 和 响应头

        

      请求头中,页面支持的压缩类型有 gzip,所以,我们可以对这个页面进行 gzip压缩

      响应头中,页面传输数据长度为1830

      接下来看一下特性代码中 OnActionExecuting 函数

            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                string acceptEncoding = filterContext.HttpContext.Request.Headers["accept-encoding"];
                if (string.IsNullOrEmpty(acceptEncoding))
                    return;
                else
                {
                    if (acceptEncoding.ToLower().Contains("gzip"))
                    {
                        // 页面支持 gzip压缩
                        var response = filterContext.HttpContext.Response;
                        response.Filter = new GZipStream(response.Filter,CompressionMode.Compress);//对响应流进行gzip压缩
                        response.AddHeader("content-encoding", "gzip");//告诉浏览器要解压
                    }
                }
            }

      给About添加特性后

        

       回复的页面传输数据长度为 716 ,比之前少了很多,内容编码为gzip,浏览器会自动对页面进行解压

  • 相关阅读:
    idea 控制到不能输出中文
    后台学习
    carthage和cocoapods
    如何优雅地调试
    从一次内存峰值说起
    多线程单线程,同步异步,并发并行,串行队列并行队列,看这里就对了
    iOS网络层设计感想
    iOS团队风格的统一
    AFNetworking二次封装的那些事
    UITextFiled,UITextView长度限制
  • 原文地址:https://www.cnblogs.com/wskxy/p/9441887.html
Copyright © 2020-2023  润新知