ASP.NET Core Filter
Filter 简介
1、切面编程机制,在 ASP.NET Core 特定的位置执行我们的自定义的代码
2、ASP.NET Core 中的 Filter 的五种类型:Authorization filter、Resource filter、Action filter、Exception filter、Result filter
3、所有筛选器一般有同步和异步两个版本
ExceptionFilter
ExceptionFilter
实现异常处理,是利用切面编程编程机制,通过builder.Services.Configure()
在适当的时机切入。需要实现IAsyncExceptionFilter
接口。
支持链式执行
public class MyExceptionFilter : IAsyncExceptionFilter
{
private readonly IWebHostEnvironment _webHostEnvironment;
public MyExceptionFilter(IWebHostEnvironment webHostEnvironment)
{
_webHostEnvironment = webHostEnvironment;
}
public Task OnExceptionAsync(ExceptionContext context)
{
// context.Exception 代表异常信息对象
// 如果给 context.ExceptionHandled 赋值为 true,则其他 ExceptionFilter 不再执行
// context.Result 的值会被返回给客户端
// 判断是否为开发模式
string message = _webHostEnvironment.IsDevelopment() ? context.Exception.ToString() : "服务器发生未处理异常";
ObjectResult result = new(new
{
code = 500,
message = message
});
context.Result = result;
context.ExceptionHandled = true;
return Task.CompletedTask;
}
}
- 在 Program.cs 中配置
MvcOptions
添加MyExceptionFilter
通过下面的方式注入的代码处于DI管理当中,所有
MyExceptionFilter
中是可以注入我们需要的服务的。
builder.Services.Configure<MvcOptions>(option =>
{
// 如果类型设置了 ExceptionHandled 为 true 需要注意 Add 的顺序先加入的后执行
option.Filters.Add<MyExceptionFilter>();
});
ActionFilter
ActionFilter 与 ExceptionFilter 不同的是 ActionFilter 实在 Controller 中的每一个 action 方法执行前或执行后都可以执行。
ActionFilter 是可以在每一个执行之前和执行之后,执行自定义代码的机制。
多个 ActionFilter 也是可以进行链式执行。
ActionFilter 具有两段代码称为 前代码 和 后代码,
顺序,先执行前代码,再执行真正的ActionFilter中的自定义代码,再执行后代码
public class MyActionFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
Console.WriteLine("ActionFilter 前代码");
ActionExecutedContext result = await next();
if (result.Exception != null)
{
Console.WriteLine("ActionFilter:发生异常");
}
else
{
Console.WriteLine("ActionFilter:执行成功");
}
}
}
[Route("[controller]/[action]")]
[ApiController]
public class TestController : ControllerBase
{
[HttpGet]
public string Test1()
{
//string str = System.IO.File.ReadAllText("f:/1.txt");
Console.WriteLine("action 代码");
return "123";
}
}
ActionFilter 实现请求限流
请求限流在实际情况中还是很常见的,最常见的就是防止恶意爬虫导致的服务器宕机。
/// <summary>
/// 请求限流器
/// </summary>
public class RateLimitActionFilter : IAsyncActionFilter
{
private readonly IMemoryCache _memoryCache;
public RateLimitActionFilter(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
}
public Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
string removeIP = context.HttpContext.Connection.RemoteIpAddress.ToString();
string cachKey = $"LastVisitTick_{removeIP}";
long? lastTick = _memoryCache.Get<long?>(cachKey);
if (lastTick is null || Environment.TickCount64 - lastTick > 1000)
{
_memoryCache.Set(cachKey, Environment.TickCount64, TimeSpan.FromSeconds(5));
return next();
}
context.Result = new ContentResult { StatusCode = StatusCodes.Status429TooManyRequests };
return Task.CompletedTask;
}
}
UseExceptionHandler —— 中心化全局异常处理
UseExceptionHandler
扩展方法能够将ExceptionHandler
中间件注册到 Asp.net Core 的 请求处理管道 中,然后在IExceptionHandlerFeature
接口的实例中获取异常对象。
public class ErrorMessage
{
/// <summary>
/// 错误消息
/// </summary>
public string? Message { get; set; }
/// <summary>
/// 堆栈跟踪信息
/// </summary>
public string? Stacktrace { get; set; }
}
using Microsoft.AspNetCore.Diagnostics;
using ServiceExceptionHandling;
using System.Net;
using System.Text.Json;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseExceptionHandler(builder =>
{
builder.Run(async context =>
{
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.ContentType = "application/json";
var exception = context.Features.Get<IExceptionHandlerFeature>();
if (exception is not null)
{
ErrorMessage error = new()
{
Message = exception.Error.Message,
Stacktrace = exception.Error.StackTrace
};
string errorOjb = JsonSerializer.Serialize(error);
await context.Response.WriteAsync(errorOjb).ConfigureAwait(false);
}
});
});
app.UseAuthorization();
app.MapControllers();
app.Run();