ActionFilter
ActionFilter
# 多个ActionFilter存在时:
1、只有一个ActionFilter执行了await next(),那么一定会执行await next()下面的代码
2、若异常发生第一个ActionFilter await next()的前后代码中,那程序程序会被终止,且异常不会被其他ActionFilter捕获
3、若异常发生其他ActionFilter await next()的前后代码中,异常都可以被其他ActionFilter捕获,且发生异常的那个地方以下的代码将不会执行
4、Action中发生异常所有的ActionFilter后代码还会执行并都将捕获到异常信息
1、方法过滤器实现事务回滚
2、异步方法中的事务
# 在一个存在await的异步方法中,TransactionScope需要在构造函数中传入TransactionScopeAsyncFlowOption,否则报错
A TransactionScope must be disposed on the same thread that it was created.
# 因为在同步状态下TransactionScope内部其实是去找了ThreadLocal(相当于当前线程的全局上下文),所以可以知晓所有数据变化,作出回滚
# 而在异步下,就得去找异步版的ThreadLocal--AsyncLocal,所以TransactionScopeAsyncFlowOption相当于是告诉TransactionScope去激活AsyncLocal
3、ActionFilter结合特性并实现事务回滚
NotTransationAttribute.cs
using System;
namespace Application
{
/// <summary>
/// 定义特性
/// </summary>
[AttributeUsage(AttributeTargets.All)]
public class NotTransationAttribute : Attribute
{
}
}
ActionFilter.cs
using Application;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Linq;
using System.Threading.Tasks;
using System.Transactions;
namespace Infrastructure
{
public class TransationScopeFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// 当前被执行的Action里面的描述信息:context.ActionDescriptor
// 当前被执行的Actionmi里外面都有的描述信息: ControllerActionDescriptor
// 为什么需要ControllerActionDescriptor呢?因为asp net core 不仅仅只有webapi/mvc,还有blazer、razor、pages等等,所以context.ActionDescriptor的类型是符合多元化的,但是具体是哪个需要自己指明,这里就指定了使用webapi/mvc的ControllerActionDescriptor
// 所以 ControllerActionDescriptor是继承自context.ActionDescriptor。
ControllerActionDescriptor ctrlActionDesc = context.ActionDescriptor as ControllerActionDescriptor;
bool isTx = false;
//如果方法或控制器上标记了NotTransationAttribute则为true
bool hasNotTransationAttribute = ctrlActionDesc.ControllerTypeInfo.GetCustomAttributes(typeof(NotTransationAttribute),false).Any()
|| ctrlActionDesc.MethodInfo.GetCustomAttributes(typeof(NotTransationAttribute), false).Any();
isTx = !hasNotTransationAttribute;
//标记则走事务
if (isTx)
{
using (TransactionScope tx = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
var result = await next();
if (result.Exception == null)
{
tx.Complete();
}
}
}
else//否则直接放行
{
await next();
}
}
}
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
//添加服务
services.Configure<MvcOptions>(opt=> {
//如果有多个ActionFilter,此ActionFilter应排在第一个,目的是把其他ActionFilter中也有数据库操作的一并回滚
opt.Filters.Add<TransationScopeFilter>();
});
services.AddDbContext<MyDbContext>(opt => {
opt.UseSqlServer("Server=.;Database=tx;Trusted_Connection=True;");
});
}
WeatherForecastController.cs
using Application;
using Domain;
using Infrastructure;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using System.Transactions;
namespace ActionFilter.Controllers
{
[ApiController]
[Route("[controller]")]
//[NotTransationAttribute]
public class WeatherForecastController : ControllerBase
{
private readonly MyDbContext db;
public WeatherForecastController(MyDbContext db)
{
this.db = db;
}
//============================通过ActionFilter和Attribute使用TransactionScope====================================
/// <summary>
/// 测试TransationScopeFilter
/// </summary>
/// <returns></returns>
[HttpPost("ActionFilterAttribute1")]
public async Task<string> Test8()
{
db.Persons.Add(new Person { Name = "zyf", Age = 18 });
await db.SaveChangesAsync();
db.Books.Add(new Book { Name = "梦回金沙湾", Price = 88 });
await db.SaveChangesAsync();
return "ok";
}
/// <summary>
/// 标记NotTransationAttribute不使用TransationScopeFilter
/// </summary>
/// <returns></returns>
[NotTransationAttribute]
[HttpPost("ActionFilterAttribute2")]
public async Task<string> Test9()
{
db.Persons.Add(new Person { Name = "zyf", Age = 18 });
await db.SaveChangesAsync();
db.Books.Add(new Book { Name = "梦回金沙湾", Price = 88 });
await db.SaveChangesAsync();
return "ok";
}
}
}
# 结论:
# Book.cs和Person.cs我都限制Name属性长度为3。
执行ActionFilterAttribute1方法:由于此方法没有标记[NotTransationAttribute],你将会发现数据库的Person添加成功和Book添加失败
执行ActionFilterAttribute2方法:由于此方法标记[NotTransationAttribute],你将会发现数据库的Person和Book都添加失败
# 项目源码:04-ActionFilter自动启动事务小项目
https://github.com/zpp99love/NetCore.g
4、ActionFilter结合缓存实现请求限流
将ip存入缓存中,并同时设置绝对滑动、随机过期时间,防止缓存雪崩等问题
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律