《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倍

 

posted @ 2022-10-31 23:17  functionMC  阅读(348)  评论(0编辑  收藏  举报