Asp Net Core Filter(过滤器)
## 1.Asp Net Core Filter(过滤器)
1.1 Filter简介
(1)面向切面编程
(2)ASP.NET Core中的Filter的五种类型:Authorization filter、Resource filter、Action filter、Exception filter、Result filter。所有筛选器一般有同步和异步两个版本,比如IActionFilter、IAsyncActionFilter接口。
1.2 Exception Filter
当系统中出现未经处理的异常的时候,异常筛选器就会执行
(1)继承IAsyncExceptionFilter
public class MyExceptionFilter : IAsyncExceptionFilter
{
private readonly ILogger<MyExceptionFilter> logger;
private readonly IHostEnvironment env;
public MyExceptionFilter(ILogger<MyExceptionFilter> logger, IHostEnvironment env)
{
this.logger = logger;
this.env = env;
}
public Task OnExceptionAsync(ExceptionContext context)
{
Exception exception = context.Exception;
logger.LogError(exception, "UnhandledException occured");
string message;
if (env.IsDevelopment())
{
message = exception.ToString();
}
else
{
message = "程序中出现未处理异常";
}
ObjectResult result = new ObjectResult(new { code = 500, message = message });
result.StatusCode = 500;
context.Result = result;
//设置剩下的IAsyncExceptionFilter不执行
context.ExceptionHandled = true;
return Task.CompletedTask;
}
}
(2)IServiceCollection注入
builder.Services.Configure<MvcOptions>(options => {
options.Filters.Add<MyExceptionFilter>();
});
1.3 ActionFilter
多个Action Filter的链式执行
(1)继承IAsyncActionFilter
ActionFilter1
using Microsoft.AspNetCore.Mvc.Filters;
public class ActionFilter1 : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
Console.WriteLine("ActionFilter1:开始执行");
ActionExecutedContext r = await next();
if (r.Exception != null)
{
Console.WriteLine("MyActionFilter 1:执行失败");
}
else
{
Console.WriteLine("MyActionFilter 1:执行成功");
}
}
}
ActionFilter2
using Microsoft.AspNetCore.Mvc.Filters;
public class ActionFilter2 : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
Console.WriteLine("ActionFilter2:开始执行");
ActionExecutedContext r = await next();
if (r.Exception != null)
{
Console.WriteLine("MyActionFilter 2:执行失败");
}
else
{
Console.WriteLine("MyActionFilter 2:执行成功");
}
}
}
(2)IServiceCollection服务注入
builder.Services.Configure<MvcOptions>(opt => {
opt.Filters.Add<ActionFilter1>();
opt.Filters.Add<ActionFilter2>();
});
(3)访问接口,查看ActionFilter执行顺序
1.4 自动启用事务的ActionFilter
(1)TransactionScope
- TransactionScope实现了IDisposable接口,如果一个TransactionScope的对象没有调用Complete()就执行了Dispose()方法,则事务会被回滚,否则事务就会被提交
- TransactionScope还支持嵌套式事务
- .NET Core中的TransactionScope不像.NET FX一样有MSDTC分布式事务提升的问题。请使用最终一致性事务
(2)继承IAsyncActionFilter
这个特性标注在不需要执行事务的方法上
/// <summary>
/// 只允许写在方法上
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class NotTransactionalAttribute : Attribute
{
}
TransactionScopeFilter
public class TransactionScopeFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
bool hasNotTransactionalAttribute = false;
if (context.ActionDescriptor is ControllerActionDescriptor)
{
var actionDesc = (ControllerActionDescriptor)context.ActionDescriptor;
hasNotTransactionalAttribute = actionDesc.MethodInfo
.IsDefined(typeof(NotTransactionalAttribute));
}
if (hasNotTransactionalAttribute)
{
await next();
return;
}
using var txScope =
new TransactionScope(TransactionScopeAsyncFlowOption.Enabled);
var result = await next();
if (result.Exception == null)
{
txScope.Complete();
}
}
}
(3)IServiceCollection服务注入
builder.Services.AddDbContext<MyDbContext>(opt => {
string connStr = builder.Configuration.GetConnectionString("Default");
opt.UseSqlServer(connStr);
});
builder.Services.Configure<MvcOptions>(options =>
{
options.Filters.Add<TransactionScopeFilter>();
});
1.5请求限流的ActionFilter
实现“一秒钟内只允许最多有一个来自同一个IP地址的请求”
(1)继承IAsyncActionFilter
public class RateLimiterFilter : IAsyncActionFilter
{
private readonly IMemoryCache memCache;
public RateLimiterFilter(IMemoryCache memCache)
{
this.memCache = memCache;
}
public Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
string removeIP = context.HttpContext.Connection.RemoteIpAddress.ToString();
string cacheKey = $"LastVisitTick_{removeIP}";
long? lastTick = memCache.Get<long?>(cacheKey);
//如果上次访问时间不存在,或者访问间隔一秒内
if (lastTick == null || Environment.TickCount64 - lastTick > 1000)
{
//设置过期时间10s
memCache.Set(cacheKey, Environment.TickCount64, TimeSpan.FromSeconds(10));
return next();
}
else
{
context.Result = new ContentResult { StatusCode = 429, Content = "访问频繁" };
return Task.CompletedTask;
}
}
}
(2)IServiceCollection服务注入
builder.Services.AddMemoryCache();
builder.Services.Configure<MvcOptions>(options =>
{
options.Filters.Add<RateLimiterFilter>();
});