P7-5 筛选器
筛选器
什么是筛选器(Filter)
- 1、切面编程机制,在ASP.NET-Core特定的位置执行我们自定义的代码。
- 在ASP.NET-Core中,切面编程(Aspect-Oriented Programming, AOP)是一种编程范式,它允许开发者将横切关注点(如日志记录、事务管理、权限检查等)与业务逻辑分离,从而提高代码的模块化和可维护性。
- 2、ASP.NET-Core中的Filter的五种类型:
- 授权筛选器(Authorization filter):在执行动作方法之前检查用户是否有权限执行该操作。
- 资源筛选器(Resource filter):在执行动作方法之前和之后执行代码,可以用于执行诸如日志记录、错误处理等任务。
- 操作筛选器(Action filter):在动作方法执行之前和之后执行代码,通常用于修改动作方法的输入参数或处理动作方法的返回值。
- 异常筛选器(Exception filter):在请求处理过程中捕获和处理异常。
- 结果筛选器(Result filter):在动作方法执行并返回结果之后执行代码,可以用于修改返回给客户端的结果。
- 本课程重点讲解
异常筛选器
和操作筛选器
- 3、所有筛选器一般有同步和异步两个版本,比如IActionFilter、IAsyncActionFilter接口。
- 重点讲解异步筛选器
异常筛选器(Exception filter)
- 当系统中出现未经处理的异常的时候,异常筛选器就会执行,我们可以在异常筛选器中对异常进行处理
- 1、当系统中出现未处理异常的时候,我们需要统一给客户端返回如下格式的响应报文:{“code”:”500”,”message”:”异常信息”}。
- 如果程序是在开发环境运行,则异常信息的内容为全部异常堆栈,否则异常信息的内容固定为“程序中出现未处理异常”
- 在生产环境中,我们不能显示异常堆栈,以避免泄漏程序的机密信息
- 2、实现IAsyncExceptionFilter接口。注入IHostEnvironment 得知运行环境。
1
2
3
4
5
6
7//context.Exception代表异常信息对象
//如果给context.ExceptionHandled赋值为true,则其他ExceptionFilter不会再被执行
//context.Result的值会被输出给客户端
ObjectResult result = new ObjectResult(new { code = 500, message = message });
result.StatusCode = 500;
context.Result = result;
context.ExceptionHandled = true; - 3、全局筛选器
1
2
3
4
5
6builder.Services.Configure<MvcOptions>(options =>//多个Filter的时候,注意注册的前后位置
{
//options.Filters.Add<LogExceptionFilter>();
options.Filters.Add<MyExceptionFilter>();
options.Filters.Add<LogExceptionFilter>();
}); - 实例代码
- 模拟生产环境的效果
操作筛选器基础(Action filter)
每次ASP.NET-Core中控制器的操作方法执行的时候,操作筛选器都会被执行,我们可以在操作方法执行之前和执行方法之后执行一些代码,完成特定的功能
- 1、操作筛选器一半实现IAsyncActionFilter接口
- 2、多个Action Filter的链式执行。
- 筛选器1–>筛选器2–>筛选器3 用next来对接
- 这是前代码
- 筛选器3–>筛选器2–>筛选器1
- 这是后代码
- 测试
- 筛选器1–>筛选器2–>筛选器3 用next来对接
- 3、无论是同步还是异步的操作筛选器,都可以处理同步和异步的操作方法,区别在于操作筛选器的实现代码是同步代码还是异步代码。
1
2
3
4
5
6
7
8
9
10
11
12
13public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
Console.WriteLine("MyActionFilter 1:开始执行");//前代码
ActionExecutedContext r = await next();
if (r.Exception !=null)//后代码
{
Console.WriteLine("MyActionFilter 1:执行失败");
}
else
{
Console.WriteLine("MyActionFilter 1:执行成功");
}
}
案例:自动启用事务的操作筛选器
- 数据库事务有一个非常重要的特性,那就是
原子性
,它保证了我们低数据库的多个操作要么全部成功,要么全部失败,进而帮助我们保证业务数据的正确性。 - 但是,事务的使用是比较麻烦的,需要我们手工启用,提交及回滚事务,我们的业务代码中会充斥着事务管理的代码。针对于上述问题,我们需要实现一个对于数据库操作自动启用事务的操作筛选器。
需求
- 1、数据库事务:要么全部成功、要么全部失败。
- 2、自动化:启动、提交以及回滚事务。
- 3、当一段使用EF Core进行数据库操作的代码放到TransactionScope声明的范围中的时候,这段代码就会自动被标记为“支持事务”。
- 4、TransactionScope实现了IDisposable接口,如果一个TransactionScope的对象没有调用Complete()就执行了Dispose()方法,则事务会被回滚,否则事务就会被提交。
- 5、TransactionScope还支持嵌套式事务。
- 6、.NET-Core中的TransactionScope不像.NET Framewprk一样有MSDTC分布式事务提升的问题。请使用最终一致性事务。(具体可以看书里面的描述)
实现
用法
- 1、对于强制不进行事务控制的Action方法,请标注NotTransactionalAttribute。
- 2、开发筛选器TransactionScopeFilter;把TransactionScopeFilter注册到Program.cs中。
- 3、编写两个插入数据的代码,测试。
同步方式与异步方法
- 异步方法需要加上“TransactionScopeAsyncFlowOption.Enabled”
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31[HttpGet]
public string Test1()//同步方法
{
//ThreadLocal: 相当于当前线程的全局变量(上下文)
using (TransactionScope tx = new TransactionScope())//在TransactionScope范围中,默认标记为“支持事务”
{
dbCtx.Books.Add(new Book { Name = "NET", Price = 2 });
dbCtx.SaveChanges();//一个事务
dbCtx.Persons.Add(new Person { Name = "666666", Age = 2 });
dbCtx.SaveChanges();//一个事务
tx.Complete();
return "ok";
}
}
[HttpGet]
public async Task<string> Test2()//异步方法
{
//AsyncLocal:相当于当前异步流程的全局变量(上下文)
using (TransactionScope tx = new TransactionScope
(TransactionScopeAsyncFlowOption.Enabled))
{
dbCtx.Books.Add(new Book { Name = "NET", Price = 2 });
await dbCtx.SaveChangesAsync();//一个事务
dbCtx.Persons.Add(new Person { Name = "666666", Age = 2 });
await dbCtx.SaveChangesAsync();//一个事务
tx.Complete();
return "ok";
}
}
案例:开发请求限流器
需求
1、Action Filter可以在满足条件的时候终止操作方法的执行。
2、在Action Filter中,如果我们不调用await next(),就可以终止Action方法的执行了。
3、为了避免恶意客户端频繁发送大量请求消耗服务器资源,我们要实现“一秒钟内只允许最多有一个来自同一个IP地址的请求”。
注意
- 实现项目中,一般限速不放在应用服务器这边,一般会放在前端的网关服务器上
- 所以一般限速不会再业务代码中来实现,如果需要可以对该代码进行对应的改造
P7-5 筛选器
http://example.com/2024/10/11/Net Core2022教程/第7章:ASP.NET Core 基础组件/P7-5 筛选器/