• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

asp.netcore2.2中的过滤器/筛选器(上)

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

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

注意:Razor 页面的筛选方法。

内置筛选器处理一些任务,例如:

  • 授权(防止用户访问未获授权的资源)。
  • 确保所有请求都使用 HTTPS。
  • 响应缓存(对请求管道进行短路出路,以便返回缓存的响应)。

可以创建自定义筛选器,用于处理横切关注点。过滤器可以避免在action中编写一些重复性的代码。比如异常过滤器可以合并处理异常。

筛选器的工作原理

筛选器管道在 MVC 选择了要执行的操作(controller中的action方法)之后运行。

筛选器类型

每种筛选器类型都在筛选器管道中的不同阶段(上图中的mvc action invocation pipeline)执行。

  • 如果请求未获授权,它们可以让管道短路。

//startup:
public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc(action =>
            {
                
                action.Filters.Add<AuthorizationFilter>();
            }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}

//authorizationfilter:
 public class AuthorizationFilter : IAsyncAuthorizationFilter
    {
        private readonly ILoggerFactory loggerFactory;

        public AuthorizationFilter(ILoggerFactory loggerFactory)
        {
            this.loggerFactory = loggerFactory;
        }
        public Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            var logger = loggerFactory.CreateLogger<AuthorizationFilter>();
            logger.LogWarning($"authorization filter is executing now ,target action is :{context.ActionDescriptor.DisplayName}");
            return Task.CompletedTask;
        }
    }

 

 

  • 它们在模型绑定之前运行,所以可以影响模型绑定。

//startup:
 public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc(action =>
            {
                action.Filters.Add<AuthorizationFilter>();
                action.Filters.Add<ResourceFilter>();
            }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }
//resourcefilter:
 public class ResourceFilter : IAsyncResourceFilter
    {
        private readonly ILoggerFactory loggerFactory;

        public ResourceFilter(ILoggerFactory loggerFactory)
        {
            this.loggerFactory = loggerFactory;
        }
        public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
        {
            var logger = loggerFactory.CreateLogger<ResourceFilter>();
            logger.LogWarning($"resource filter is executing now,valueproviderfactories count:{context.ValueProviderFactories.Count}");
            var executedContext = await next();
            logger.LogWarning($"resource filter is executed now ,result's type is {executedContext.Result.GetType().Name}");

        }
    }

  • 它们可用于处理传入某个操作的参数以及从该操作返回的结果。

//startup:
public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc(action =>
            {
                action.Filters.Add<ActionsFilter>();
                action.Filters.Add<AuthorizationFilter>();
                action.Filters.Add<ResourceFilter>();
            }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }
//actionsfilter
public class ActionsFilter : IAsyncActionFilter
    {
        private readonly ILoggerFactory factory;

        public ActionsFilter(ILoggerFactory factory)
        {
            this.factory = factory;
        }
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            var logger = factory.CreateLogger<ActionsFilter>();
            logger.LogWarning($"action filter is executing new ,context.modelstate:{context.ModelState.IsValid}");
            var executedContext = await next();
            logger.LogWarning($"action filter is executed now,executedContext controller:{executedContext.Controller.ToString()}");
        }
    }

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

 //startup:
public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc(action =>
            {
                action.Filters.Add<ActionsFilter>();
                action.Filters.Add<AuthorizationFilter>();
                action.Filters.Add<ResourceFilter>();
                action.Filters.Add<ExceptionsFilter>();
            }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }
//exceptionsfilter:
 public class ExceptionsFilter : IAsyncExceptionFilter
    {
        private readonly ILoggerFactory loggerFactory;

        public ExceptionsFilter(ILoggerFactory loggerFactory)
        {
            this.loggerFactory = loggerFactory;
        }
        public Task OnExceptionAsync(ExceptionContext context)
        {
            var logger = loggerFactory.CreateLogger<ExceptionsFilter>();
            logger.LogWarning($"some exception's happened,exception's message:{context.Exception.Message}");
context.Result=new ObjectResult(context.Exception.Message);//这个异常被处理了一下,以200正常返回。
return Task.CompletedTask; } }

上面的日志打印结果可以看出exception filter实在authorization filter和resource filter以及action filter之后执行的它能捕获的异常是在action执行过程中发生的异常。所以,如果在authorization filter或者resource filter中发生异常的话,它是没有办法捕获的,可以做一个测验:将authorization filter中抛出一个异常:

可以看到这个异常是被直接抛出来了,并没有被exception handler中进行处理。接着改在resource filter中抛出一个异常,看看:

同样,在resource filter中抛出的异常exception filter也是处理不了的。也就是说在筛选器管道中,处于exception筛选器执行之前而执行的代码抛出的异常,exception筛选器是处理不了的。要想捕获程序的全局异常,我觉得应该在中间件中定义对异常的捕获。这个结论还没有进行证实,有时间再讨论。

  • 对于必须围绕视图或格式化程序的执行的逻辑,它们很有用。

//startup:
 public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc(action =>
            {
                action.Filters.Add<ActionsFilter>();
                action.Filters.Add<AuthorizationFilter>();
                action.Filters.Add<ResourceFilter>();
                action.Filters.Add<ExceptionsFilter>();
                action.Filters.Add<ResultFilter>();
            }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }
//resultfilter:
 public class ResultFilter : IAsyncResultFilter
    {
        private readonly ILoggerFactory loggerFactory;

        public ResultFilter(ILoggerFactory loggerFactory)
        {
            this.loggerFactory = loggerFactory;
        }
        public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
        {
            var logger = loggerFactory.CreateLogger<ResultFilter>();
            logger.LogWarning($"result filter is executing, context.result is :{context.Result.GetType().Name}");
            var executedContext = await next();
            logger.LogWarning($"result filter is executed ,context.result is {executedContext.Result.GetType().Name}");
        }
    }

上面的结果是action中没有抛出异常,正常执行的结果,如果在action中抛出异常:

上下对比一下会发现,result filter只会在action正常执行没有抛出异常之后才会执行。exception filter是会捕获action抛出的异常。

下图展示了这些筛选器类型在筛选器管道中的交互方式。

实现

通过不同的接口定义,筛选器同时支持同步和异步实现。例如我上面举的例子全部都是用异步的方式实现的。

例如,在调用操作方法之前调用 OnActionExecuting,在操作方法返回之后调用 OnActionExecuted

 

using FiltersSample.Helper;
using Microsoft.AspNetCore.Mvc.Filters;

namespace FiltersSample.Filters
{
    public class SampleActionFilter : IActionFilter
    {
        public void OnActionExecuting(ActionExecutingContext context)
        {
            // do something before the action executes
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            // do something after the action executes
        }
    }
}

例如,ActionExecutionDelegate 调用该操作方法(如果没有下一个action filter)或下一个操作筛选器(下一个action filter),用户可以在调用它之前和之后执行代码。

ActionFilterAttribute 类实现 IActionFilter 和 IResultFilter,以及它们的异步等效接口。

 

注意:同步和异步的只需要实现一个就行,如果两个都实现了,会优先执行异步版本的。

篇幅太长,再来一片吧。


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
asp.net多个域名重定向,在web.Config中配置发布时间:2022-07-10
下一篇:
ASP.NET Core 中的会话和状态管理(微软文档)发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap