《ASP.NET Core技术内幕与项目实战》精简集-WebApi3.3:筛选器filter
本节内容,涉及到7.6(P229-P242),以WebApi说明为主。主要NuGet包:无
一、图解筛选器及其与中间件的关系
1、上图涵盖了中间件和筛选器,中间件是AspNetCore层面的构件,更加底层;而筛选器是属于MVC/WebApi中间件的构建。两者的执行逻辑有相似之处,但它们作用在不同层面。
2、筛选器包括5种类型:授权筛选器、资源筛选器、操作筛选器、异常筛选器、结果筛选器。作用于不同的切面,即在MVC中间件中特定位置或时机,执行我们自定义的代码。其中授权、资源、结果筛选器,只有我们自己开发框架时会使用到,大多数情况,我们主要自定义操作筛选器和异常筛选器。
二、自定义一个异常筛选器
1 //创建一个异常筛选器类,实现IAsyncExceptionFilter。MyExceptionFilter.cs 2 public class MyExceptionFilter : IAsyncExceptionFilter 3 { 4 private readonly ILogger<MyExceptionFilter> _logger; 5 private readonly IHostEnvironment _hostEnvironment; 6 public MyExceptionFilter(ILogger<MyExceptionFilter> logger, IHostEnvironment hostEnvironment) 7 { 8 _logger = logger; 9 _hostEnvironment = hostEnvironment; 10 } 11 12 public Task OnExceptionAsync(ExceptionContext context) 13 { 14 var exception = context.Exception; 15 _logger.LogError(exception, "程序中出现未处理异常"); 16 17 string message; 18 if (_hostEnvironment.IsDevelopment()) 19 { 20 message = exception.ToString(); 21 } 22 else 23 { 24 message = "程序中出现未处理异常"; 25 } 26 27 var result = new ObjectResult(new { code = 500, message = message}); 28 result.StatusCode = 500; 29 context.Result = result; 30 context.ExceptionHandled = true; 31 return Task.CompletedTask; 32 } 33 } 34 35 36 //通过配置选项方式,配置MvcOptions,增加MyExceptionFilter筛选器。Program.cs 37 builder.Services.Configure<MvcOptions>(opt => 38 { 39 opt.Filters.Add<MyExceptionFilter>(); 40 });
代码解读:
2行:必须实现IAsyncExceptionFilter,有同步和异步,推荐使用异步
4-10行:注入ILogger和IHostEnviroment服务
12行:实现方法OnExceptionAsync,参数ExceptionContext类型,框架调用筛选器时,会自动传入异常上下文
14行:通过context.Exception,获得异常对象
27-30行:设置响应报文的内容。其中context.ExceptionHandled的值为true,告诉AspNetCore不再执行默认的异常响应逻辑。
37-40行:通过选项方式,配置MvcOptions,增加MyExceptionFilter
三、自定义一个操作筛选器
1 //定义第一个操作筛选器 2 //MyActionFilter1.cs 3 public class MyActionFilter1 : IAsyncActionFilter 4 { 5 public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) 6 { 7 Console.WriteLine("MyActionFilter1,开始执行"); 8 ActionExecutedContext result = await next(); 9 if (result.Exception != null) 10 { 11 Console.WriteLine("MyActionFilter1,执行失败"); 12 } 13 else 14 { 15 Console.WriteLine("MyActionFilter1,执行成功"); 16 } 17 } 18 } 19 20 21 //定义第二个操作筛选器 22 //MyActionFilter2 .cs 23 public class MyActionFilter2 : IAsyncActionFilter 24 { 25 public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) 26 { 27 Console.WriteLine("MyActionFilter1,开始执行"); 28 ActionExecutedContext result = await next(); 29 if (result.Exception != null) 30 { 31 Console.WriteLine("MyActionFilter1,执行失败"); 32 } 33 else 34 { 35 Console.WriteLine("MyActionFilter1,执行成功"); 36 } 37 } 38 } 39 40 41 //配置筛选器 42 //Program.cs 43 builder.Services.Configure<MvcOptions>(opt => 44 { 45 opt.Filters.Add<MyActionFilter1>(); 46 opt.Filters.Add<MyActionFilter2>(); 47 }); 48 49 50 //执行结果,控制台输出以下结果 51 MyActionFilter1,开始执行 52 MyActionFilter1,开始执行 53 执行GetData控制器方法 54 MyActionFilter1,执行成功 55 MyActionFilter1,执行成功
代码解读:
3行:操作筛选器必须实现IAsyncActionFilter接口
5行:方法OnExceptionAsync的参数:①方法执行的上下文context,可以获得方法参数、描述、控制器等一系列信息;②委托next,指向下一个筛选器或控制器方法。框架调用过滤器时,会自动传入相应对象。
8行:next()方法,返回方法的执行结果,如果出现方法执行异常,可以通过result.Exception获得异常对象
四、自动启用事务的操作筛选器
//定义一个操作筛选器类TransactionScopeFilter.cs //启动一个事务 using var txScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enable); //进入下一个操作筛选器或控制器方法,并获取方法的执行结果 var result = await next(); //如果操作方法执行的结果没有异常,则提交事务 if(result.Exception == null) { txScope.Complete } //操作方法中有多个数据库操作 [HttpPost] public async Task Save() { ctx.Books.Add(new Book{Id = 1, Name = "abc"}); await ctx.SaveChangeAsync(); //如果这里抛出一个异常,即使上面已经操作数据库,仍然会回滚取消 //throw new Exception() ctx.Books.Add(new Book{Id = 2, Name = "efg"}); await ctx.SaveChangeAsync(); }
特别说明:
1、本系列内容主要基于杨中科老师的书籍《ASP.NET Core技术内幕与项目实战》及配套的B站视频视频教程,同时会增加极少部分的小知识点
2、本系列教程主要目的是提炼知识点,追求快准狠,以求快速复习,如果说书籍学习的效率是视频的2倍,那么“简读系列”应该做到再快3-5倍