• .net core 5.0 之 五种Filter


    官方文档:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/controllers/filters?view=aspnetcore-5.0

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

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

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

    可以创建自定义筛选器,用于处理横切关注点。 横切关注点的示例包括错误处理、缓存、配置、授权和日志记录。 筛选器可以避免复制代码。 例如,错误处理异常筛选器可以合并错误处理。

    筛选器的工作原理

    筛选器在 ASP.NET Core 操作调用管道(有时称为筛选器管道)内运行。 筛选器管道在 ASP.NET Core 选择了要执行的操作之后运行。

    筛选器类型

    每种筛选器类型都在筛选器管道中的不同阶段执行:

    • 授权筛选器(AuthorizationFilter):最先运行,用于确定是否已针对请求为用户授权。 如果请求未获授权,授权筛选器可以让管道短路。

    • 资源筛选器(ResourceFilter):

      • 授权后运行。
      • OnResourceExecuting在筛选器管道的其余阶段之前运行代码。 例如,OnResourceExecuting 在模型绑定之前运行代码。
      • OnResourceExecuted 在管道的其余阶段完成之后运行代码。
    • 操作筛选器(ActionFilter):

      • 在调用操作方法之前和之后立即运行代码。
      • 可以更改传递到操作中的参数。
      • 可以更改从操作返回的结果。
      • 不可在 Pages 中使用。
    • 异常筛选器(ExceptionFilter):在向响应正文写入任何内容之前,对未经处理的异常应用全局策略。

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

    筛选器实现

    筛选器通过不同的接口定义支持同步和异步实现。同步筛选器在其管道阶段之前和之后运行代码。 例如,OnActionExecuting 在调用操作方法之前调用。 OnActionExecuted 在操作方法返回之后调用。

    筛选器接口的同步和异步版本任意实现一个,而不是同时实现 。 运行时会先查看筛选器是否实现了异步接口,如果是,则调用该接口,调用之后就不会执行同步代码。

    操作筛选器(ActionFilter)

    继承 ActionFilterAttribute 就可以了,可以看到 ActionFilterAttribute 继承了 IResultFilter , 所以实现了结果筛选器的一些方法,如果只想实现操作筛选器,可以直接继承 Attribute, IActionFilter / IAsyncActionFilter

     代码:

            [FcbActionFilter("hello")]
            [HttpGet("api/{controller}/{action}/{id?}")]
            public IActionResult test()
            {
                Console.WriteLine("执行方法体");
                return Ok(HttpContext.Request.Headers.FirstOrDefault(x=>x.Key== _configuration.GetSection("admin").Value).Value);
            }    
    
        public class FcbActionFilterAttribute : ActionFilterAttribute
        {
            private string _msg { get; set; }
            public FcbActionFilterAttribute(string msg )
            {
                _msg = msg;
            }
            public override void OnActionExecuting(ActionExecutingContext context)
            {
                Console.WriteLine("方法过滤之前");
            }
            public override void OnActionExecuted(ActionExecutedContext context)
            {
                Console.WriteLine("方法过滤之后");
            }
            public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
            {
                IConfiguration _configuration = context.HttpContext.RequestServices.GetService(typeof(IConfiguration)) as IConfiguration;
                context.HttpContext.Request.Headers.Add(_configuration.GetSection("admin").Value, _msg);
                Console.WriteLine("异步方法过滤之前");
                var resultContext = await next();
                Console.WriteLine("异步方法过滤之后");
            }
            public override void OnResultExecuting(ResultExecutingContext context)
            {
                Console.WriteLine("结果过滤之前");
            }
            public override void OnResultExecuted(ResultExecutedContext context)
            {
                Console.WriteLine("结果过滤之后");
            }
            public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
            {
                Console.WriteLine("异步结果过滤之前");
                var resultContext = await next();
                Console.WriteLine("异步结果过滤之后");
            }
    
        }

     执行结果:

    异步方法过滤之前
    执行方法体
    异步方法过滤之后
    异步结果过滤之前
    异步结果过滤之后

    这里可以看到先执行操作筛选器,再执行方法体,最后执行结果筛选器

    结果筛选器(ResultFilter)

    继承 ResultFilterAttribute 就可以了,当然也可以继承上面操作筛选器的  ActionFilterAttribute   

    代码:

            [FcbResultFilter]
            [HttpGet("api/{controller}/{action}/{id?}")]
            public IActionResult test()
            {
                Console.WriteLine("执行方法体");
                return Ok(HttpContext.Request.Headers.FirstOrDefault(x=>x.Key== _configuration.GetSection("admin").Value).Value);
            }    
    

      

    public class FcbResultFilterAttribute : ResultFilterAttribute
        {
            //由于有异步不执行
            public override void OnResultExecuting(ResultExecutingContext context)
            {
                Console.WriteLine("结果过滤之前");
            }
            //由于有异步不执行
            public override void OnResultExecuted(ResultExecutedContext context)
            {
                Console.WriteLine("结果过滤之后");
            }
            public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
            {
                Console.WriteLine("异步结果过滤之前");
                var resultContext = await next();
                Console.WriteLine("异步结果过滤之后");
            }
        }
    

      

    执行结果:

    执行方法体
    异步结果过滤之前
    异步结果过滤之后
    

      

    资源筛选器(ResourceFilter)

    继承  IResourceFilter / IAsyncResourceFilter  

    代码:

    [FcbActionFilter("hello")]
            [FcbResourceFilter]
            [HttpGet("api/{controller}/{action}/{id?}")]
            public IActionResult test()
            {
                Console.WriteLine("执行方法体");
                return Ok();
            }
     public class FcbResourceFilterAttribute : Attribute, IResourceFilter
        {
            public void OnResourceExecuting(ResourceExecutingContext context)
            {
                Console.WriteLine("资源过滤之前");
            }
            public void OnResourceExecuted(ResourceExecutedContext context)
            {
                Console.WriteLine("资源过滤之后");
            }
        }
    
    public class FcbActionFilterAttribute : ActionFilterAttribute
        {
            private string _msg { get; set; }
            public FcbActionFilterAttribute(string msg )
            {
                _msg = msg;
            }
            public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
            {
                Console.WriteLine("异步方法过滤之前");
                var resultContext = await next();
                Console.WriteLine("异步方法过滤之后");
            }
            public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
            {
                Console.WriteLine("异步结果过滤之前");
                var resultContext = await next();
                Console.WriteLine("异步结果过滤之后");
            }
    
        }

    运行结果:

    资源过滤之前
    异步方法过滤之前
    执行方法体
    异步方法过滤之后
    异步结果过滤之前
    异步结果过滤之后
    资源过滤之后
    

      

    授权筛选器(AuthorizationFilter)

    • 是筛选器管道中运行的第一个筛选器。
    • 控制对操作方法的访问。
    • 具有在它之前的执行的方法,但没有之后执行的方法。

    不会在授权筛选器中引发异常,在授权筛选器出现异常时请小心应对。

    代码:

    [FcbAuthorizationFilter("index")]
    [FcbResourceFilter]
    [HttpGet("api/{controller}/{action}/{id?}")]
    public IActionResult test()
    {
        
        Console.WriteLine("执行方法体");
        return Ok();
    }
    
    public class FcbAuthorizationFilterAttribute : Attribute,IAuthorizationFilter
    {
        public string _value;
        public FcbAuthorizationFilterAttribute(string value)
        {
            _value = value;
        }
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            if (_value == "index")
            {
                Console.WriteLine("资源授权成功");
            }
            else
            {
                context.Result = new ContentResult()
                {
                    StatusCode = 401,
                    Content = "没有权限"
                };
            }
        }
    }
    public class FcbResourceFilterAttribute : Attribute, IResourceFilter
    {
        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            Console.WriteLine("资源过滤之前");
        }
        public void OnResourceExecuted(ResourceExecutedContext context)
        {
            Console.WriteLine("资源过滤之后");
        }
    }

    运行结果:

    资源授权成功
    资源过滤之前
    执行方法体
    资源过滤之后
    

    异常筛选器(ExceptionFilter)

    • 没有之前和之后的事件。
    • 实现 OnException 或 OnExceptionAsync。
    • 处理 Razor 页面或控制器创建、Razor、操作筛选器或操作方法中发生的未经处理的异常。
    • 请不要捕获资源筛选器、结果筛选器或 MVC 结果执行中发生的异常。

    若要处理异常,将 属性 ExceptionHandled 设置为 或 true 分配 Result 属性。 这将停止传播异常。 异常筛选器无法将异常转变为“成功”。 只有操作筛选器才能执行该转变

    代码:

    [FcbResultFilter]
    [HttpGet("api/{controller}/{action}/{id?}")]
    public IActionResult test()
    {
        
        Console.WriteLine("执行方法体");
        throw new Exception("抛出异常");
        return Ok();
    }
    public class FcbResultFilterAttribute : ResultFilterAttribute
    {
        public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
        {
            Console.WriteLine("异步结果过滤之前");
            var resultContext = await next();
            Console.WriteLine("异步结果过滤之后");
        }
    }
    
    public class FcbExceptionFilterAttribute: ExceptionFilterAttribute
        {
            public override Task OnExceptionAsync(ExceptionContext context)
            {
                Console.WriteLine(context.Exception.Message);
                context.Result = new ObjectResult(new
                {
                    code = 500,
                    message = context.Exception.Message
                });
                return Task.CompletedTask;
            }
        }
    

      将异常注册在服务里面设置全局监控异常,当然也可以通过特性的方式监控某个接口或控制器

    public void ConfigureServices(IServiceCollection services)
            {
                services.AddControllersWithViews(configure=> {
                    configure.Filters.Add(typeof(FcbExceptionFilterAttribute));
                });
                
            }
    

      运行结果:

    执行方法体
    抛出异常
    

    控制器级别筛选器

    除了以上几种筛选器,这里还隐藏了一个控制里面的筛选器,继承自  Controller  基类的每个控制器都包括   Controller.OnActionExecuting 、 Controller.OnActionExecutionAsync  和   Controller.OnActionExecuted  方法。 这些方法:

    • 覆盖为给定操作运行的筛选器。
    • OnActionExecuting 在所有操作筛选器之前调用。
    • OnActionExecuted 在所有操作筛选器之后调用。
    • OnActionExecutionAsync 在所有操作筛选器之前调用。 next 之后的筛选器中的代码在操作方法之后运行。

    代码:

    public class HomeController : Controller
        {
            private readonly ILogger<HomeController> _logger;
            private IConfiguration _configuration;
            public HomeController(ILogger<HomeController> logger, IConfiguration configuration)
            {
                _logger = logger;
                _configuration = configuration;
            }
            public override void OnActionExecuting(ActionExecutingContext context)
            {
            //通过设置Result来实现短路,就不会执行接下来的操作筛选器 //context.Result =Ok("异常"); // Do something before the action executes. Console.WriteLine("控制器筛选器执行之前"); base.OnActionExecuting(context); } public override void OnActionExecuted(ActionExecutedContext context) { // Do something after the action executes. Console.WriteLine("控制器筛选器执行之后"); base.OnActionExecuted(context); } [HttpGet("api/{controller}/{action}/{id?}")] public IActionResult test() { Console.WriteLine("执行方法体"); return Ok(HttpContext.Request.Headers.FirstOrDefault(x=>x.Key== _configuration.GetSection("admin").Value).Value); } }

      

    运行结果:

    控制器筛选器执行之前
    异步方法过滤之前
    执行方法体
    异步方法过滤之后
    控制器筛选器执行之后
    异步结果过滤之前
    异步结果过滤之后

    取消和设置短路

    通过设置提供给筛选器方法的 ResourceExecutingContext 参数上的 Result 属性,可以使筛选器管道短路。 例如,以下资源筛选器将阻止执行管道的其余阶段:

    public class ShortCircuitingResourceFilterAttribute : Attribute, IResourceFilter
    {
        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            context.Result = new ContentResult()
            {
                Content = "Resource unavailable - header not set."
            };
        }
    
        public void OnResourceExecuted(ResourceExecutedContext context)
        {
        }
    }
    

      

  • 相关阅读:
    人工智能系统
    Maven tomcat插件配置和使用
    青春谁不糊涂3
    假设但是学习java入门,请离开SSH稍远
    Linux下top订购具体解释
    Unity3d + NGUI 多分辨率适应
    Delphi 注册文件类型 设置文件图标
    如何创建自定义的文件类型关联
    delphi 中字符串与16进制、10进制转换函数
    十六进制字符串转化成字符串输出HexToStr(Delphi版、C#版)
  • 原文地址:https://www.cnblogs.com/roubaozidd/p/16054356.html
Copyright © 2020-2023  润新知