首页 > 其他分享 >.NET Core 中的筛选器 Filter

.NET Core 中的筛选器 Filter

时间:2023-03-14 16:56:55浏览次数:47  
标签:Core Console WriteLine 异步 public Filter context NET 筛选

官方文档: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

代码:

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("异步结果过滤之后");
    }

}

使用过滤器:

[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);
}

执行结果:

1 异步方法过滤之前
2 执行方法体
3 异步方法过滤之后
4 异步结果过滤之前
5 异步结果过滤之后

执行顺序:OnActionExecuting-->OnActionExecuted --> Controller(构造函数 --> 方法) --> OnResultExecuting-->OnResultExecuted

IActionFilter能干什么?
1.登录(授权) :不推荐,应该放在最外层做控制,最好在IAuthorizationFilter中实现
2.日志 :非常推荐,跟执行顺序有关,效果非常好;
3.缓存 :可以做,但是不推荐,最好在IResourceFilter中实现,如上图;

 

 

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

结果筛选器(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("异步结果过滤之后");
        }
    }
1 执行方法体
2 异步结果过滤之前
3 异步结果过滤之后

 

资源筛选器(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("异步结果过滤之后");
        }

    }

运行结果:

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

执行顺序:OnResourceExecuting --> Controller(构造函数 --> 方法) --> OnResourceExecuted

IResourceFilter能干什么?
1.缓存(全局资源) :ResourceFilter就是为了缓存而生的;
2.权限 :可以做,但是不推荐做这个,因为权限一般放在AuthorizeFilter中;
3.日志 :有更适合的Filter,IActionFilter

 

授权筛选器(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("资源过滤之后");
    }
}

运行结果:

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

异常筛选器(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));
            });

        }

运行结果:

1 执行方法体
2 抛出异常

 

控制器级别筛选器

除了以上几种筛选器,这里还隐藏了一个控制里面的筛选器,继承自  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)
        {<br>        //通过设置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)
    {
    }
}

 

标签:Core,Console,WriteLine,异步,public,Filter,context,NET,筛选
From: https://www.cnblogs.com/flydmxy/p/17215502.html

相关文章

  • java8 Optional使用 stream filter多级过滤
    java8Optional使用streamfilter多级过滤packagecom.example.core.mydemo.java8;publicclassMyModel{privateStringcouponCode;privateIntegeror......
  • asp.net core3.1 使用RenderSection和Section
     我们使用公共文件,常常会用到同样的头部和尾部,那么就可以使用了    <!DOCTYPEhtml><html><head><metaname="viewport"content="width=device-widt......
  • 设计神器Pixel Planet Generator!像素风动态星球在线生成器
    有没有喜欢观测宇宙的小伙伴啊?给我们讲讲宇宙有多美丽呗!在很多人的眼里,宇宙黑暗而寂静,看不到什么美丽的景色,可事实上,在天文望远镜的镜头里,黑暗的宇宙背后却是一个美丽的精......
  • 报表生成器 FastReport .Net 用户指南 2023(十二):公共对象属性
    FastReport.Net是一款全功能的WindowsForms、ASP.NET和MVC报表分析解决方案,使用FastReport.NET可以创建独立于应用程序的.NET报表,同时FastReport.Net支持中文、英语等1......
  • .netCore Swagger 发布到IIS 问题
    1.安装DotNetCore.2.0.8-WindowsHosting  2.https://dotnet.microsoft.com/en-us/download/dotnet/6.0  安装aspnetcore-runtime-6.0.11-win-x643.IIS应用池安装......
  • Blazor在IoT领域的前端实践 @.NET开发者日
    2023年3月11号,MASA技术团队参加了“.NET开发者日”,IoT项目经理郭浩在活动中做“Blazor在IoT领域的前端实践”的主题分享郭浩数闪科技IoT项目经理从事.NET开发10......
  • gRPC之.Net6中的客户端和服务端共用proto协议文件
    1、说明在上一篇文章gRPC之.Net6中的初步使用介绍中,我们简单的介绍了gRPC在服务端、客户端以及Web项目中的使用。有一个问题,不知道大家发现没有,就是不管在服务端项目还是......
  • ef执行原生sql语句_EF Core中执行原生SQL语句
    一、课程介绍之所以今天录制这个系列文章的主要原因是,想在快速帮助到大家上手在ASP.NETCoreWebAPI中结合EFCore来操作我们的数据库。EFCore的基础文章和基础课程实在是......
  • 使用EF Core 6执行原始SQL查询
    目录背景现有选项ExecuteSqlRaw插入更新删除FromSqlRawFromSqlInterpolated自定义数据库上下文扩展方法ExecuteScalarExecuteNonQueryFromSqlQueryFromSqlRaw......
  • .NET中委托性能的演变
    .NET中的委托.NET中的委托是一项重要功能,可以实现间接方法调用和函数式编程。自.NETFramework1.0起,委托在.NET中就支持多播(multicast)功能。通过多播,我们可以在单个委托......