一、什么是Filter?
-
切面编程机制,在ASP.Net Core特定的位置执行我们的自定义代码
-
ASP.NET Core中有Filter的五种类型:
Authorization filter
(权限验证)Resource filter
(资源缓存)Action filter
(模型验证/日志记录)Exception filter
(异常捕获)Result filter
(处理返回结果)
-
所有筛选器一般有两个版本,比如
IActionFilter
、IAsyncActionFilter
二、Exception filter
当系统中出现未经处理的异常的时候,异常筛选器就会执行
-
新建一个API控制器
TestController
-
在控制器中编写一个会抛异常的方法,代码如下:
[HttpGet] public string Test1() { string s = System.IO.File.ReadAllText("D:1.txt"); return s; }
-
调用方法
Test1
后,会出现以下界面
-
当系统中出现未处理异常的时候,假设我们需要统一返回给客户端一个如下格式的响应报文:
{"code":"500","message":"异常信息"}
,可以通过一个实现了IAsyncExceptionFilter
接口的类来实现,类的代码如下:public class MyExceptionFilter : IAsyncExceptionFilter { private readonly IWebHostEnvironment webHost; public MyExceptionFilter(IWebHostEnvironment webHost) { this.webHost = webHost; } public Task OnExceptionAsync(ExceptionContext context) { string message; if (webHost.IsDevelopment()) { message = context.Exception.ToString(); //context.Exception 代表异常信息对象 } else { message = "服务器端发生未处理异常!"; } ObjectResult objectResult = new ObjectResult(new { code = 500, message = message }); context.Result = objectResult; //context.Result的值会被输入给客户端 context.ExceptionHandled = true; //如果赋值为True,则其他的ExceptionFilter不会再执行 return Task.CompletedTask; } }
-
全局注册
builder.Services.Configure<MvcOptions>(opt => { opt.Filters.Add<MyExceptionFilter>(); });
-
调用方法
Test1
后,会出现以下界面:
三、Action filter
-
实现
IAsyncActionFilter
接口 -
多个Action Filter的链式执行,执行顺序如下:
-
在TestController中插入以下代码:
[HttpGet] public string Test1() { Console.WriteLine("开始执行 Test1"); string s = System.IO.File.ReadAllText("D:1.txt"); return s; } [HttpGet] public DateTime GetDateTime() { Console.WriteLine("开始执行 GetDateTime"); return DateTime.Now; }
-
新建一个实现了
IAsyncActionFilter
接口的类MyActionFilter
:public class MyActionFilter : IAsyncActionFilter { public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { Console.WriteLine("MyActionFilter 开始执行..."); //在Action之前执行 ActionExecutedContext result = await next(); //在Action之后执行 if(result.Exception == null) { Console.WriteLine("MyActionFilter 执行成功了!"); } else { Console.WriteLine("MyActionFilter 发生异常了!"); } } }
-
分别调用两个方法可以看到控制台中显示以下内容:
四、实现一个自动启用事务的Action Filter
-
创建一个类
NotTransactionAttribute
,继承自Attribute
,且只能标注到方法上[AttributeUsage(AttributeTargets.Method)] public class NotTransactionAttribute : Attribute { }
-
创建一个类
TransactionScopeFilter
,实现了IAsyncActionFilter
接口public class TransactionScopeFilter : IAsyncActionFilter { public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { //context.ActionDescriptor 当前被执行的Action方法的描述信息 ControllerActionDescriptor? controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor; bool isTx = false; //是否进行事务控制 if (controllerActionDescriptor != null) { //查找当前Action方法的Attribute,是否标记了NotTransactionAttribute //如果标记了NotTransactionAttribute,则返回True,就不进行事务控制 bool hasNotTransactionAttribute = controllerActionDescriptor.MethodInfo.GetCustomAttributes(typeof(NotTransactionAttribute), false).Any(); isTx = !hasNotTransactionAttribute; } if (isTx) { using (TransactionScope ts = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)) { var r = await next(); if (r.Exception == null) { ts.Complete(); } } } else { await next(); } } }