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();

相关文章
|
机器学习/深度学习 计算机视觉
YOLOv11改进策略【Neck】| NeurIPS 2023 融合GOLD-YOLO颈部结构,强化小目标检测能力
YOLOv11改进策略【Neck】| NeurIPS 2023 融合GOLD-YOLO颈部结构,强化小目标检测能力
1073 9
YOLOv11改进策略【Neck】| NeurIPS 2023 融合GOLD-YOLO颈部结构,强化小目标检测能力
|
前端开发 C# 容器
浅谈WPF之控件拖拽与拖动
使用过office的visio软件画图的小伙伴都知道,画图软件分为两部分,左侧图形库,存放各种图标,右侧是一个画布,将左侧图形库的图标控件拖拽到右侧画布,就会生成一个新的控件,并且可以自由拖动。那如何在WPF程序中,实现类似的功能呢?今天就以一个简单的小例子,简述如何在WPF中实现控件的拖拽和拖动,仅供学习分享使用,如有不足之处,还请指正。
635 2
|
JSON 前端开发 API
一文讲清 API 接口的概念、设计和实现
总结 在这个例子中,我们创建了一个简单的Express服务器,并定义了一个/api/auth/login的POST接口来处理登录请求。我们使用body-parser中间件来解析请求体中的JSON数据,并在接口内部进行简单的用户名和密码验证。
|
Web App开发 安全 前端开发
EDGE的使用心得和深度探索
EDGE的使用心得和深度探索
|
数据采集 供应链 监控
一文读懂如何评估组织的数据价值并采取行动【值得收藏】
最近数据资产建设成为大型集团及组织的热点,那么如何评估或衡量数据价值成为大家最为关切的话题!
一文读懂如何评估组织的数据价值并采取行动【值得收藏】
|
机器学习/深度学习 搜索推荐 算法
优酷视频基于用户兴趣个性化推荐的挑战和实践
本文将介绍一下优酷个性化搜索推荐的服务,优酷在视频个性化搜索推荐里用户兴趣个性化表达碰到的挑战和问题,当前工业界常用的方法,以及我们针对这些问题的尝试。
4473 0
|
9天前
|
缓存 测试技术 API
Qwen 3.7 Plus 与 Max 实测:性价比与多模态能力差异解析(2026)
2026 年 6 月 1 日,阿里悄无声息地发布了 Qwen 3.7 Plus,距 Qwen 3.7 Max 上线刚好 11 天。同样的 1M 上下文,同样的 35 小时自治上限。但价格才是头条:Plus 是 0.40/M输入,Max是 2.50/M——便宜约 6 倍——并且还能看图、看视频。Vision Arena 上 Plus 已经排到 #16。所以这周真正值得讨论的问题不是”要不要为视觉能力买单”,而是”Max 凭什么用 6 倍价格换来 2 个百分点的 benchmark 领先”。
|
9天前
|
JavaScript 定位技术 API
CodeGraph 爆火:编程 Agent 需要的不是更多上下文,而是一张提前画好的代码地图
CodeGraph 是一款爆火的本地代码智能工具,通过 tree-sitter 解析 AST 构建结构化知识图谱(存于 SQLite),为编程 Agent 提前生成“代码地图”。它显著降低 Agent 在中大型项目中的探索成本——实测工具调用减少71%、Token 降57%、速度提升46%,支持19+语言及主流框架路由识别,完全离线、无需 API Key。
770 10
CodeGraph 爆火:编程 Agent 需要的不是更多上下文,而是一张提前画好的代码地图

热门文章

最新文章