使用.NET 6开发TodoList应用(12)——实现ActionFilter
系列导航及源代码
需求
Filter在.NET Web API项目开发中也是很重要的一个概念,它运行在执行MVC响应的Pipeline中执行,允许我们将一些可以在多个Action之间重用的逻辑抽取出来集中管理。虽然我们在上一篇使用.NET 6开发TodoList应用(11)——使用FluentValidation和MediatR实现接口请求验证中演示了如何通过使用MediatR提供的IPipelineBehavior接口在CQRS的Handle方法执行前后插入可重用代码,而本文所演示的Filters作用在Controller的Action执行或Action返回结果前后。
可以创建自定义Filters,用于处理应用程序中的横切片关注点。 横切片关注点的包括错误处理、缓存、配置、授权和日志记录。 Filters可以避免重复代码。
Filter的类型分为以下几种:
Authorization Filters:最先运行,用于确定是否已针对请求为用户授权。 如果请求未获授权,Authorization Filters可以让管道短路。Resource Filters:授权后运行。OnResourceExecuting在Filter Pipeline的其余阶段之前运行代码。OnResourceExecuted在管道的其余阶段完成之后运行代码。可以用这个类型的Filter进行缓存和性能统计。Action Filters:在调用操作方法之前和之后立即运行代码。它可以更改传递到操作中的参数,也可以更改从操作返回的结果,当然如果什么都不更改仅作记录也是可以的。Exception Filters:在向响应正文写入任何内容之前,对未经处理的异常应用全局策略。Result Filters:在执行操作结果返回之前和之后运行代码。 仅当操作方法成功执行时,它们才会被运行。
这五种Filters在Filter Pipeline中直观的展现是这样的:

而整个FIlter Pipeline在完整的Middleware Pipeline中的阶段是这样的:

在本文中,我们将演示Action Filters是如何在Controller的Action执行前后记录请求和响应日志的。
目标
使用Action Filters进行接口日志记录。
原理与思路
创建一个自定义的Action Filter,用于实现Controller的接口日志逻辑。
实现
在Api新建文件夹Filters并创建类LogFilterAttribute:
LogFilterAttribute.cs
using System.Text.Json;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace TodoList.Api.Filters;
public class LogFilterAttribute : IActionFilter
{
private readonly ILogger<LogFilterAttribute> _logger;
public LogFilterAttribute(ILogger<LogFilterAttribute> logger) => _logger = logger;
public void OnActionExecuting(ActionExecutingContext context)
{
var action = context.RouteData.Values["action"];
var controller = context.RouteData.Values["controller"];
// 获取名称包含Command的参数值
var param = context.ActionArguments.SingleOrDefault(x => x.Value.ToString().Contains("Command")).Value;
_logger.LogInformation($"Controller:{controller}, action: {action}, Incoming request: {JsonSerializer.Serialize(param)}");
}
public void OnActionExecuted(ActionExecutedContext context)
{
var action = context.RouteData.Values["action"];
var controller = context.RouteData.Values["controller"];
// 需要先将Result转换为ObjectResult类型才能拿到Value值
var result = (ObjectResult)context.Result!;
_logger.LogInformation($"Controller:{controller}, action: {action}, Executing response: {JsonSerializer.Serialize(result.Value)}");
}
}
依赖注入:
Program.cs
builder.Services.AddScoped<LogFilterAttribute>();
在需要应用该Filter的Controller Action上添加属性:
TodoListController.cs
[HttpPost]
[ServiceFilter(typeof(LogFilterAttribute))]
public async Task<ApiResponse<Domain.Entities.TodoList>> Create([FromBody] CreateTodoListCommand command)
{
return ApiResponse<Domain.Entities.TodoList>.Success(await _mediator.Send(command));
}
验证
启动Api项目,执行创建TodoList的请求:
请求

响应
来自于
OnActionExecuting的请求数据日志:
注意在我们上一篇文章中的
Handling CreateTodoListCommand之前输出的内容。以及来自于
OnActionExecuted输出的返回数据日志:
一点扩展
关于Filter的主题还包含关于其作用域,优先级顺序以及如何调整优先级等,其他主题像如何改写响应,如何进行性能统计和缓存,我在这里暂时不做演示,可以参考微软官方文档:ASP.NET Core 中的筛选器,进行更多了解。
总结
在本文中我们通过一个很简单的例子,演示了Action Filter的基本用法。至此我们关于请求中间件管道的讨论先告一个段落,后面说到认证鉴权的时候我们还会回来讨论这个主题。
从下一篇开始,我们集中来讨论查询操作中涉及的一些典型场景:包括分页、排序、过滤、搜索等。
参考资料
使用.NET 6开发TodoList应用(12)——实现ActionFilter的更多相关文章
- 使用.NET 6开发TodoList应用(3)——引入第三方日志库
需求 在我们项目开发的过程中,使用.NET 6自带的日志系统有时是不能满足实际需求的,比如有的时候我们需要将日志输出到第三方平台上,最典型的应用就是在各种云平台上,为了集中管理日志和查询日志,通常会选 ...
- 使用.NET 6开发TodoList应用(1)——系列背景
前言 想到要写这样一个系列博客,初衷有两个:一是希望通过一个实践项目,将.NET 6 WebAPI开发的基础知识串联起来,帮助那些想要入门.NET 6服务端开发的朋友们快速上手,对使用.NET 6开发 ...
- 使用.NET 6开发TodoList应用(2)——项目结构搭建
为了不影响阅读的体验,我把系列导航放到文章最后了,有需要的小伙伴可以直接通过导航跳转到对应的文章 : P TodoList需求简介 首先明确一下我们即将开发的这个TodoList应用都需要完成什么功能 ...
- 使用.NET 6开发TodoList应用(4)——引入数据存储
需求 作为后端CRUD程序员(bushi,数据存储是开发后端服务一个非常重要的组件.对我们的TodoList项目来说,自然也需要配置数据存储.目前的需求很简单: 需要能持久化TodoList对象并对其 ...
- 使用.NET 6开发TodoList应用(5)——领域实体创建
需求 上一篇文章中我们完成了数据存储服务的接入,从这一篇开始将正式进入业务逻辑部分的开发. 首先要定义和解决的问题是,根据TodoList项目的需求,我们应该设计怎样的数据实体,如何去进行操作? 长文 ...
- 使用.NET 6开发TodoList应用(5.1)——实现Repository模式
需求 经常写CRUD程序的小伙伴们可能都经历过定义很多Repository接口,分别做对应的实现,依赖注入并使用的场景.有的时候会发现,很多分散的XXXXRepository的逻辑都是基本一致的,于是 ...
- 使用.NET 6开发TodoList应用(6)——使用MediatR实现POST请求
需求 需求很简单:如何创建新的TodoList和TodoItem并持久化. 初学者按照教程去实现的话,应该分成以下几步:创建Controller并实现POST方法:实用传入的请求参数new一个数据库实 ...
- 使用.NET 6开发TodoList应用文章索引
系列导航 使用.NET 6开发TodoList应用(1)--系列背景 使用.NET 6开发TodoList应用(2)--项目结构搭建 使用.NET 6开发TodoList应用(3)--引入第三方日志 ...
- 开发错误日记 12: Unsupported major.minor version 52.0
开发错误日记 12: Unsupported major.minor version 52.0 在编译时出现如下错误: java.lang.UnsupportedClassVersionError: ...
随机推荐
- python生成器浅析
A 'generator' is a function which returns a generator iterator. It looks like a normal function exce ...
- LeetCode382-链表随机节点
原题链接:[382. 链表随机节点]:https://leetcode-cn.com/problems/linked-list-random-node/ 题目描述: 给定一个单链表,随机选择链表的一个 ...
- 从源码看RequestMappingHandlerMapping的注册与发现
1.问题的产生 日常开发中,大多数的API层中@Controller注解和@RequestMapping注解都会被使用在其中,但是为什么标注了@Controller和@RequestMapping注解 ...
- MySQL(3):SELECT语法
一,数据库语句 数据库数据是通过DML语句管理数据库数据,包括: INSERT (添加数据语句) UPDATE (更新数据语句) DELETE (删除数据语句) 1:INSERT (添加数据语句) I ...
- java多线程并发编程中的锁
synchronized: https://www.cnblogs.com/dolphin0520/p/3923737.html Lock:https://www.cnblogs.com/dolphi ...
- 基于Web的质量和测试度量指标
直观了解软件质量和测试的完整性 VectorCAST/Analytics可提供便于用户理解的web仪表盘视图来显示软件代码质量和测试完整性指标,让用户能够掌握单个代码库的趋势,或对比多个代码库的度量指 ...
- Mysql资料 Binlog
目录 一.简介 二.开启binlog及相关参数 开启 相关操作 三.查看binlog日志 使用mysqlbinlog自带查看命令法 mysql加载方式查询 四.恢复数据 五.命令参数 一.简介 MyS ...
- 阿里云RDS备份 恢复到本地
目录 一.恢复准备 二.具体操作 一.恢复准备 阿里云RDS默认配置了全备份+binlog,可以精准恢复到某个时间点上. 可以下载备份的包到本地,进行本地恢复,要预留好本地的数据库容量和cpu等规格, ...
- LeetCode 36. Valid Sudoku (Medium)
题目 Determine if a 9 x 9 Sudoku board is valid. Only the filled cells need to be validated according ...
- PHP数组函数总结与使用
array_change_key_case(数组,CASE_LOWER/CASE_UPPER) 数组键值转化为小写CASE_LOWER/大写CASE_UPPER array_chunk(数组,分割 ...