.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,浏览器会自动对页面进行解压

原文地址:https://www.cnblogs.com/wskxy/p/9441887.html