当前位置: 首页 > news >正文

ASP.NET Core Filter

目录

什么是Filter?

Exception Filter

实现

注意

ActionFilter

注意

案例:自动启用事务的筛选器

事务的使用

TransactionScopeFilter的使用


什么是Filter?

  1. 切面编程机制,在ASP.NET Core特定的位置执行我们自定义的代码。
  2. ASP.NET Core中的Filter的五种类型:Authorization filter、Resource filter、Action filter、Exception filter、Result filter。本书中重点讲解Exception filter和Action filter。
  3. 所有筛选器一般有同步和异步两个版本,比如IActionFilter、IAsyncActionFilter接口。

Exception Filter

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

实现

  1. 当系统中出现未处理异常的时候,我们需要统一给客户端返回如下格式的响应报文:{“code”:”500”,”message”:”异常信息”}。
    对于开发环境中message是异常堆栈,对于其他环境message用一个general的报错信息。
  2. 实现IAsyncExceptionFilter接口。注入IHostEnvironment得知运行环境。
public class LogExceptionFilter : IAsyncExceptionFilter
{public Task OnExceptionAsync(ExceptionContext context){return File.AppendAllTextAsync("F:/error.log", context.Exception.ToString());}
}public class MyExceptionFilter : IAsyncExceptionFilter
{private readonly IWebHostEnvironment hostEnv;public MyExceptionFilter(IWebHostEnvironment hostEnv){this.hostEnv = hostEnv;}public Task OnExceptionAsync(ExceptionContext context){//context.Exception代表异常信息对象//context.ExceptionHandled为true时,表示异常已经被处理,其他ExceptionFilter将不会再处理//context.Result的值会返回给客户端string msg;if (hostEnv.IsDevelopment()){msg = context.Exception.Message;}else{msg = "服务器发生了未处理异常";}ObjectResult objresult = new ObjectResult(new { code = 500, message = msg });context.Result = objresult;context.ExceptionHandled = true;return Task.CompletedTask;}
}

注意

ExceptionFilter执行顺序与注册顺序有关,后注册的先执行

builder.Services.Configure<MvcOptions>(opt =>
{opt.Filters.Add<MyExceptionFilter>();opt.Filters.Add<LogExceptionFilter>();
});

ActionFilter

IAsyncActionFilter接口

多个Action Filter的链式执行。

注意

ActionFilter执行顺序与注册顺序有关,先注册的先执行

public class MyActionFilter1 : IAsyncActionFilter
{public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next){Console.WriteLine("MyActionFilter1前代码");ActionExecutedContext result = await next();if (result.Exception != null){Console.WriteLine("MyActionFilter1捕获到异常");}else{Console.WriteLine("MyActionFilter1后代码");}}
}
builder.Services.Configure<MvcOptions>(opt =>
{opt.Filters.Add<MyActionFilter1>();opt.Filters.Add<MyActionFilter2>();
});

案例:自动启用事务的筛选器

  1. 数据库事务:要么全部成功、要么全部失败。
  2. 自动化:启动、提交以及回滚事务。
  3. 当一段使用EF Core进行数据库操作的代码放到TransactionScope声明的范围中的时候,这段代码就会自动被标记为“支持事务”。
  4. TransactionScope实现了IDisposable接口,如果一个TransactionScope的对象没有调用Complete()就执行了Dispose()方法,则事务会被回滚,否则事务就会被提交。
  5. TransactionScope还支持嵌套式事务。
  6. .NET Core中的TransactionScope不像.NET FX一样有MSDTC分布式事务提升的问题。请使用最终一致性事务。

事务的使用

[HttpPost]
public async Task<string> Test2()
{using (TransactionScope tx = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)){dbctx.Books.Add(new Book { Title = "计算机网络", Price = 12.6 });await dbctx.SaveChangesAsync();dbctx.People.Add(new Person { Name = "张三", Age = 20 });await dbctx.SaveChangesAsync();tx.Complete();return "OK";}
}[HttpPost]
public string Test1()
{using (TransactionScope tx = new TransactionScope()){dbctx.Books.Add(new Book { Title = "计算机网络", Price = 12.6 });dbctx.SaveChangesAsync();dbctx.People.Add(new Person { Name = "张三", Age = 20 });dbctx.SaveChangesAsync();tx.Complete();return "OK";}
}

TransactionScopeFilter的使用

对于强制不进行事务控制的Action方法,请标注NotTransactionalAttribute。

开发筛选器TransactionScopeFilter;把TransactionScopeFilter注册到Program.cs中。

NotTransationAttribute.cs:
[AttributeUsage(AttributeTargets.Method)]
public class NotTransationAttribute:Attribute
{
}TransactionScopeFilter.cs:
public class TransactionScopeFilter : IAsyncActionFilter
{public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next){//context.ActionDescriptor中是当前被执行的Action的描述信息//context.ActionArguments中是当前被执行的Action的参数信息ControllerActionDescriptor controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;//if (controllerActionDescriptor == null)//不是一个MVC的Actionbool isTX = false;//是否进行事务控制if (controllerActionDescriptor != null){//获取当前Action是否有NotTransationAttribute特性bool hasNotTransationAttribute = controllerActionDescriptor.MethodInfo.GetCustomAttributes(typeof(NotTransationAttribute), false).Any();//如果没有NotTransationAttribute特性,则进行事务控制isTX = !hasNotTransationAttribute;}if (isTX){//创建一个异步的事务范围using (TransactionScope tx=new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)){var r= await next();if (r.Exception==null){tx.Complete();}}}else{await next();}}
}Program.cs:
builder.Services.Configure<MvcOptions>(opt =>
{opt.Filters.Add<TransactionScopeFilter>();
});

 案例:开发请求限流器

需求

  1. Action Filter可以在满足条件的时候终止操作方法的执行。
  2. 在Action Filter中,如果我们不调用await next(),就可以终止Action方法的执行了。
  3. 为了避免恶意客户端频繁发送大量请求消耗服务器资源,我们要实现“一秒钟内只允许最多有一个来自同一个IP地址的请求”。
public class ratelimitActionFilter : IAsyncActionFilter
{private readonly IMemoryCache memcache;public ratelimitActionFilter(IMemoryCache memcache){this.memcache = memcache;}public Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next){//从HTTP请求的上下文中获取客户端的远程IP地址string removeIP = context.HttpContext.Connection.RemoteIpAddress.ToString();//context.ActionDescriptor中是当前被执行的Action的描述信息,转换为ControllerActionDescriptor类型ControllerActionDescriptor controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;//构建缓存的Keystring cacheKey = $"LastVisitTick_{controllerActionDescriptor.ControllerName}_{removeIP}";//从缓存中获取上次访问的时间戳long? lastTick = memcache.Get<long?>(cacheKey);//如果上次访问的时间戳不存在或者距离当前时间已经超过1秒if (lastTick == null || Environment.TickCount64 - lastTick > 1000){//设置当前的时间戳到缓存中memcache.Set(cacheKey, Environment.TickCount64, TimeSpan.FromSeconds(10));//避免长期不访问的用户一直占用缓存return next();}else{context.Result = new ContentResult{StatusCode = 429,Content = "访问太频繁,请稍后再试!"};return Task.CompletedTask;}}
}

http://www.lryc.cn/news/531245.html

相关文章:

  • doris:删除操作概述
  • 【思维导图】redis
  • 申博经验贴
  • .Net Core笔记知识点(跨域、缓存)
  • YOLOV11-1:YoloV11-安装和CLI方式训练模型
  • 自学习记录-编程语言的特点(持续记录)
  • TypeScript (TS) 和 JavaScript (JS)
  • 【HarmonyOS之旅】基于ArkTS开发(二) -> UI开发三
  • 如何选择Spring AOP的动态代理?JDK与CGLIB的适用场景?
  • 手机连接WIFI可以上网,笔记本电脑连接WIFI却不能上网? 解决方法?
  • MySQL不适合创建索引的11种情况
  • 树莓派pico入坑笔记,故障解决:请求 USB 设备描述符失败,故障码(43)
  • GRE阅读双线阅读 --青山学堂GRE全程班 包括 阅读、数学、写作、填空、背单词
  • 98,【6】 buuctf web [ISITDTU 2019]EasyPHP
  • Kamailio、MySQL、Redis、Gin后端、Vue.js前端等基于容器化部署
  • 知识管理系统助力企业信息共享与创新思维的全面提升研究
  • Leetcode 131 分割回文串(纯DFS)
  • 结构体DMA串口接收比特错位
  • 用FormLinker实现自动调整数据格式,批量导入微软表单
  • 技术架构师成长路线(2025版)
  • 独立开发者的技术栈
  • wordpress每隔24小时 随机推荐一个指定分类下的置顶内容。
  • Android13源码下载和编译过程详解
  • C++底层学习预备:模板初阶
  • 使用mybatisPlus插件生成代码步骤及注意事项
  • 扩散模型(二)
  • java异常处理——try catch finally
  • 新月军事战略分析系统使用手册
  • Docker Hub 镜像 Pull 失败的解决方案
  • SQL进阶实战技巧:如何构建用户行为转移概率矩阵,深入洞察会话内活动流转?