7.5筛选器(过滤器)

简介: 筛选器运行开发人员在ASP.NET Core特定的位置执行我们自己的代码,比如在控制器的操作方法之前执行数据检查,或者在ActionResult执行的时候向响应报文头中加入自定义数据。

7.5筛选器(过滤器)

筛选器运行开发人员在ASP.NET Core特定的位置执行我们自己的代码,比如在控制器的操作方法之前执行数据检查,或者在ActionResult执行的时候向响应报文头中加入自定义数据。

异常筛选器

系统中出现未处理异常的时候,就会自动执行异常筛选器

  1. 编写筛选器

usingMicrosoft.AspNetCore.Mvc;

usingMicrosoft.AspNetCore.Mvc.Filters;

//异步异常筛选器要实现IAsyncExceptionFilter接口

publicclassMyExceptionFilter : IAsyncExceptionFilter

{

   //由于筛选器中需要把异常写入日志,并且要判断运行环境,所以加入这两个服务

   privatereadonlyILogger<MyExceptionFilter>logger;

   privatereadonlyIHostEnvironmentenv;

   publicMyExceptionFilter(ILogger<MyExceptionFilter>logger, IHostEnvironmentenv)

   {

       this.logger=logger;

       this.env=env;

   }

   publicTaskOnExceptionAsync(ExceptionContextcontext)

   {

       Exceptionexception=context.Exception;//获取异常对象

       logger.LogError(exception, "UnhandledException occured");//将异常写入日志

       stringmessage;

       if (env.IsDevelopment())//如果是开发环境

       {

           message=exception.ToString();

       }

       else

       {

           message="程序中出现未处理异常";

       }

       //响应报文头文件

       ObjectResultresult=newObjectResult(new { code=500, message=message });

       result.StatusCode=500;

       context.Result=result;

       //告诉ASP.NET Core不再执行默认的响应逻辑

       context.ExceptionHandled=true;

       returnTask.CompletedTask;

   }

}

  1. 设置全局筛选器,在Program.cs的builder.Build之前添加

//MvcOptions是ASP.NET Core项目的主要配置对象,这是新的用法

builder.Services.Configure<MvcOptions>(options=>

{//注册全局筛选器,这样ASP.NET Core所有未处理的异常都可以被MyMyExceptionFilte处理

   options.Filters.Add<MyExceptionFilter>();

});

操作筛选器

控制器中操作方法执行的时候,操作筛选器就会被执行,通常可以在操作方法执行之前或者之后执行一些代码

操作筛选器要实现IAsyncActionFilter接口,接口中定义了

public async Task OnActionExecutionAsync(ActionExecutingContext context,   ActionExecutionDelegate next)方法

context:代表Action执行的上下文对象,从context中可以获取请求路径等信息

next:用来指向下一个操作器的委托,一个项目可以有多个操作筛选器,如果当前操作筛选器是最后一个筛选器则next就是要执行的操作方法

  1. 编写操作筛选器1

usingMicrosoft.AspNetCore.Mvc.Filters;

publicclassMyActionFilter1 : IAsyncActionFilter

{

   publicasyncTaskOnActionExecutionAsync(ActionExecutingContextcontext,

       ActionExecutionDelegatenext)

   {

       Console.WriteLine("MyActionFilter 1:开始执行");

       //next之前的代码是在操作方法执行之前要执行的代码

       ActionExecutedContextr=awaitnext();//执行下一个筛选器,

        //如果next出现异常,则ActionExecutedContext.Exception则为异常对像,如果没有异常

           //则使用ActionExecutedContext.Result获取

        //next之后的代码是在操作方法执行之后要执行的代码

       if (r.Exception!=null)

       {

           Console.WriteLine("MyActionFilter 1:执行失败");

       }

       else

       {

           Console.WriteLine("MyActionFilter 1:执行成功");

       }

   }

}

  1. 编写操作筛选器2

usingMicrosoft.AspNetCore.Mvc.Filters;

publicclassMyActionFilter2 : IAsyncActionFilter

{

   publicasyncTaskOnActionExecutionAsync(ActionExecutingContextcontext,

       ActionExecutionDelegatenext)

   {

       Console.WriteLine("MyActionFilter 2:开始执行");

       ActionExecutedContextr=awaitnext();

       if (r.Exception!=null)

       {

           Console.WriteLine("MyActionFilter 2:执行失败");

       }

       else

       {

           Console.WriteLine("MyActionFilter 2:执行成功");

       }

   }

}

  1. 在Program.cs注册筛选器

builder.Services.Configure<MvcOptions>(options=>

{

   options.Filters.Add<MyActionFilter1>();//注册顺序及时执行顺序

   options.Filters.Add<MyActionFilter2>();

});

  1. 在控制器中增加操作方法

[HttpGet]

publicstringGetData()

{

   Console.WriteLine("执行GetData");

   return"hello";

}

  1. 结果

案例1 自动启用事务

数据库事务保证了我们对数据的操作要么全部成功,要么全部失败,我们可以使用TransactionScope来操作数据库事务,将使用EF Core的数据库操作放到TransactionScope声明的范围内,则这段代码自动支撑事务。

  1. 我们定义数据库操作都默认使用事务,对于不使用事务的方法,使用NotTransactionAttribute来标记

[AttributeUsage(AttributeTargets.Method)]

publicclassNotTransactionalAttribute : Attribute{}

  1. 实现筛选器

publicclassTransactionScopeFilter : IAsyncActionFilter

{

   publicasyncTaskOnActionExecutionAsync(ActionExecutingContextcontext, ActionExecutionDelegatenext)

   {

       boolhasNotTransactionalAttribute=false;

       //判断是否标注了NotTransactionalAttribute

       if (context.ActionDescriptorisControllerActionDescriptor)

       {

           varactionDesc= (ControllerActionDescriptor)context.ActionDescriptor;

           hasNotTransactionalAttribute=actionDesc.MethodInfo

               .IsDefined(typeof(NotTransactionalAttribute));

       }

       //如果不想添加事务则直接使用next执行

       if (hasNotTransactionalAttribute)

       {

           awaitnext();

           return;

       }

       //用using声明作用域,将所有数据库操作都包含进该作用域中

       //因为OnActionExecutionAsync是异步,所以要使用TransactionScopeAsyncFlowOption.Enabled

       //表示作用域会跨线程

       usingvartxScope=

               newTransactionScope(TransactionScopeAsyncFlowOption.Enabled);

       varresult=awaitnext();

       if (result.Exception==null)

       {

           txScope.Complete();//如果没有异常则提交事务

       }

   }

}

  1. 注册到Program.cs中

builder.Services.Configure<MvcOptions>(options=>

{

   options.Filters.Add<TransactionScopeFilter>();

});

案例2:请求限流器

如果有客户端频繁发送请求而消耗服务器资源,则可以限制1s内只允许同一个IP的一次请求

usingMicrosoft.AspNetCore.Mvc;

usingMicrosoft.AspNetCore.Mvc.Filters;

usingMicrosoft.Extensions.Caching.Memory;

publicclassRateLimitFilter : IAsyncActionFilter

{

   privatereadonlyIMemoryCachememCache;//记录上一次的访问时间

   publicRateLimitFilter(IMemoryCachememCache)

   {

       this.memCache=memCache;

   }

   publicTaskOnActionExecutionAsync(ActionExecutingContextcontext,

           ActionExecutionDelegatenext)

   {

       //获取用户IP

       stringremoveIP=context.HttpContext.Connection.RemoteIpAddress.ToString();

       stringcacheKey=$"LastVisitTick_{removeIP}";

       long?lastTick=memCache.Get<long?>(cacheKey);//从缓存中获取上次访问的时间

       if (lastTick==null||Environment.TickCount64-lastTick>1000)//不存在或者大于1s

       {

           memCache.Set(cacheKey, Environment.TickCount64,TimeSpan.FromSeconds(10));//设置缓存

           returnnext();//执行操作方法

       }

       else//频繁访问

       {//不执行next(),即不再执行操作方法

           context.Result=newContentResult { StatusCode=429 } ;

           returnTask.CompletedTask;

       }

   }

}

注册筛选器和内存缓存服务

builder.Services.Configure<MvcOptions>(options=>

{

   options.Filters.Add<RateLimitFilter>();

});

builder.Services.AddMemoryCache();

相关文章
|
Kubernetes Linux Docker
Docker容器生产实践1——永远设置容器内存限制
背景 在默认情况下,docker容器并不会对容器内部进程使用的内存大小进行任何限制。对于PaaS系统而言,或者对于直接使用docker的用户而言,这非常危险。
4257 0
|
3月前
|
存储
Tushare接口文档:交易日历(trade_cal)
本文旨在对Tushare的交易日历trade_cal数据接口进行介绍,提供更多参考示例和使用说明。交易日历可以用来作为获取其他数据的关键(迭代)参数,也可以进行其他的应用。本文还基于交易日介绍了如何获取每周及每月最后一个交易日。
746 1
Tushare接口文档:交易日历(trade_cal)
|
2月前
|
人工智能 自然语言处理 API
阿里云百炼Token Plan全新升级:个人版39元起,企业版降价,一个API Key畅享多模态旗舰模型
阿里云百炼Token Plan重磅升级:个人版39元/月起,含Qwen3.8-Max-Preview等多模态模型;企业版标准席位直降至150元/月。统一Credits计费,支持文本、图像、视频全模态调用,夜间低至2折,预算可控、灵活升级。阿里云百炼Token Plan官网:https://t.aliyun.com/U/EsRjVx
495 0
|
4月前
|
弹性计算 应用服务中间件 Apache
阿里云301重定向全指南:从配置到SEO优化的实战手册
301重定向是HTTP永久跳转技术,用于将旧URL精准迁移至新地址,实现SEO权重近乎100%传递、避免404、统一www/HTTPS等规范。阿里云支持虚拟主机、ECS(Nginx/Apache/IIS)及CDN源站等多种配置方式,是网站改版、域名更换与安全升级的必备实践。
1056 0
|
4月前
|
人工智能 运维 安全
从OpenClaw到Hermes,企业如何构建一个系统级的安全底座来引入不同的AI工具~
OpenClaw 火起来之后,Hermes 等新的 Agent 工具继续出现,企业面对的已经不是某一个 AI 工具的选择题,而是一类正在进入办公、研发、运营和业务流程的新能力。今天尝试从本地助手、部门级托管环境、企业级 Agent 中台三种路径切入,分析不同架构适合的阶段与边界,介绍一下 FinClaw 和 FinSafe 如何帮助企业把 Agent 纳入统一身份、权限、工具、审计和执行安全体系。
267 0
|
5月前
|
人工智能 IDE JavaScript
通义灵码深度评测-企业内部使用实战
通义灵码深度评测-企业内部使用实战 ,根据企业内部使用实战,建设了微信公众号、视频号、csdn专栏,持续更新了通义灵码企业级实践教程,从入门->精通,从基本功能->高阶功能全面详尽的实战,持续更新中
978 0
|
6月前
|
人工智能 物联网 API
以一杯奶茶为例,带你读懂这35个大模型核心概念
用“奶茶制作”类比大模型核心概念,生动解析数据集、预训练、Token、Prompt、RLHF、RAG、LoRA、多模态、AI Agent等40+术语,轻松理解技术本质,告别名词焦虑!
729 3
|
算法 Java
闲话银行家舍入法,以及在程序中如何实现
闲话银行家舍入法,以及在程序中如何实现
1240 0
|
存储 SQL 人工智能
Apache Flink 2.0:Streaming into the Future
本文整理自阿里云智能高级技术专家宋辛童、资深技术专家梅源和高级技术专家李麟在 Flink Forward Asia 2024 主会场的分享。三位专家详细介绍了 Flink 2.0 的四大技术方向:Streaming、Stream-Batch Unification、Streaming Lakehouse 和 AI。主要内容包括 Flink 2.0 的存算分离云原生化、流批一体的 Materialized Table、Flink 与 Paimon 的深度集成,以及 Flink 在 AI 领域的应用。
2014 13
Apache Flink 2.0:Streaming into the Future