3_筛选器

筛选器介绍

和netframework mvc里的过滤器一样。通过使用 ASP.NET Core 中的筛选器,可在请求处理管道中的特定阶段之前或之后运行代码。

内置筛选器处理任务,例如:
授权(防止用户访问未获授权的资源)。
响应缓存(对请求管道进行短路出路,以便返回缓存的响应)。
可以创建自定义筛选器,用于处理横切关注点。 横切关注点的示例包括错误处理、缓存、配置、授权和日志记录。 筛选器可以避免复制代码。 例如,错误处理异常筛选器可以合并错误处理。

筛选器分类

①操作筛选器(action级别)

可以在调用单个操作方法之前和之后立即运行代码。 它们可用于处理传入某个操作的参数以及从该操作返回的结果。 不可在 Razor Pages 中使用操作筛选器 。

创建一个Filter文件夹,里面用来存放筛选器。

新建一个MyActionFilter类,用来当作操作筛选器

namespace MyFirstNetCore.Filter
{
    //操作筛选器
    public class MyActionFilter : IActionFilter
    {
        public void OnActionExecuted(ActionExecutedContext context)
        {
            
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
            
        }
    }
}
行全局注入

然后在Startup类的ConfigureServices方法里将这个筛选器进行全局注入

 //全局注入筛选器,mvc也是一个组件,需要注入即可使用
            services.AddMvc(a =>
            {
                //注入操作筛选器
                a.Filters.Add(new MyActionFilter());
            });

这样每次运行的时候都会执行这个过滤器里的方法了。

局部注册

如果不想全局注册,想给某个控制器或者action使用的话(局部注册)

①TypeFilter 注册

在需要筛选的地方增加特性[TypeFilter(typeof(xxx))]此方式不需要在ConfigureServices 中注册。
删除Startup类的ConfigureServices方法里的全局注册,直接使用局部注册。
image

②ServiceFilter 注册

在需要拦截的地方增加特性 [ServiceFilter(typeof(xxx))] 并在ConfigureServices 中注册xxx
如:services.AddScoped(typeof(MyActionFilter));

然后在控制器或者action上面使用即可。
image


②授权筛选器

最先运行,用于确定是否已针对请求为用户授权。 如果请求未获授权,授权筛选器可以让管道短路。
在这个里面可以进行权限过滤。

namespace MyFirstNetCore.Filter
{
    //权限筛选器
    public class MyAuthorFilter : IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            //判断是否需要跳过权限验证筛选器
            if (HasAllowAnonymous(context))
                return;//跳过权限验证

            //设置路由短路
            context.Result = new ContentResult() { Content = " 你没有权限访问该页面。。。" };
        }

        //用于判断Action或控制器有没有AllowAnonymous标签,微软写的
        private bool HasAllowAnonymous(AuthorizationFilterContext context)
        {
            var filters = context.Filters;
            for (var i = 0; i < filters.Count; i++)
            {
                if (filters[i] is IAllowAnonymousFilter)
                {
                    return true;
                }
            }

            var endpoint = context.HttpContext.GetEndpoint();
            if (endpoint?.Metadata?.GetMetadata<IAllowAnonymous>() != null)
            {
                return true;
            }

            return false;
        }
    }
}

然后注入该筛选器即可

            //全局注入筛选器,mvc也是一个组件,需要注入即可使用
            services.AddMvc(a =>
            {
                //注入操作筛选器
                a.Filters.Add(new MyActionFilter());
                //注入授权筛选器
                a.Filters.Add(new MyAuthorFilter());

            });

这样访问项目里的任何过滤器都会进行验证了。如果某个控制器或action不想验证只需要在其上面加[AllowAnonymous]//绕过权限过滤器特性即可。


③结果筛选器(result级别)

可以在执行单个操作结果之前和之后立即运行代码。 仅当操作方法成功执行时,它们才会运行。 对于必须围绕视图或格式化程序的执行的逻辑,它们很有用。最后才会执行这种筛选器。

下面是一个可以向响应中插入响应头的过滤器

namespace MyFirstNetCore.Filter
{
    //结果筛选器,该过滤器继承了特性,可以方便控制作用域
    public class AddHeaderAttribute: ResultFilterAttribute
    {
        //该过滤器可以向响应里加响应头

        private readonly string _name;
        private readonly string _value;

        public AddHeaderAttribute(string name, string value)
        {
            _name = name;
            _value = value;
        }

        public override void OnResultExecuting(ResultExecutingContext context)
        {
            context.HttpContext.Response.Headers.Add(_name, new string[] { _value });
            base.OnResultExecuting(context);
        }

    }
}

只需要在action或者控制器上加该过滤器的特性即可向响应体里插入响应头。如:
image

这样响应报文里的响应头就有加的了。
image

也可以通过全局注入的方式,不过这样用户每次请求不管请求的是什么控制器都会响应这个响应头了。


④异常筛选器

用于在向响应正文写入任何内容之前,对未经处理的异常应用全局策略。


筛选器作用域

全局注入(Startup类里注入即可)
局部(只限制控制器或只限制action,使用特性的方式)

筛选器优先级

授权筛选器 -> 异常筛选器 -> 操作筛选器 -> 结果筛选器
同一类型筛选器可以通过注入顺序或者设置Order值来修改优先级

筛选器管道中的交互方式

image



筛选器里进行构造函数注入

如,下面这个行为筛选器需要进行构造函数注入。

namespace MyFirstNetCore.Filter
{
    //操作筛选器
    public class MyActionFilter : IActionFilter
    {
        private readonly IUserDAL _userDAL;

        public MyActionFilter(IUserDAL userDAL)
        {
            this._userDAL = userDAL;
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
           string name= _userDAL.GetName();
        }
    }
}

直接在ConfigureServices方法里注入即可,然后在里面传递构造函数所需要的参数即可

    //全局注入筛选器,mvc也是一个组件,需要注入即可使用
            services.AddMvc(a =>
            {
                //注入操作筛选器
                a.Filters.Add(new MyActionFilter(new UserDAL()));
            });

但是,如果已经进行过了该接口的构造 函数注入,那么,这里如果实例对象仍然是该实例不是实现该接口的其它实例,可以不用指定实例了 。因为构造函数注入里已经指定了实例了。这样还可以避免再new一个新的对象。
image

因为该筛选器里的构造函数也是需要这个接口的实例,所以如果不用指定即可不用写实例。
image

posted @ 2022-05-04 17:39  青仙  阅读(110)  评论(0编辑  收藏  举报