使用.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: ...
随机推荐
- 试了下GoAsm
在VC里我们: #include <windows.h> DWORD dwNumberOfBytesWritten; int main() { HANDLE hStdOut = GetSt ...
- C++福尔摩斯的约会
这道题的要求总结如下: 1.DAY 星期 大写字母:A B C D E F G2.HH 时 数字+大写字母 0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M ...
- IntentFilter,PendingIntent
1.当Intent在组件间传递时,组件如果想告知Android系统自己能够响应那些Intent,那么就需要用到IntentFilter对象. IntentFilter对象负责过滤掉组件无法响应和处理的 ...
- Insert into select语句引发的生产事故
前言 Insert into select请慎用.这天xxx接到一个需求,需要将表A的数据迁移到表B中去做一个备份.本想通过程序先查询查出来然后批量插入.但xxx觉得这样有点慢,需要耗费大量的网络 ...
- Simulating final class in C++
Ever wondered how can you design a class in C++ which can't be inherited. Java and C# programming la ...
- 【Linux】【Services】【SaaS】Docker+kubernetes(3. 用ansible管理机器和软件)
1. 简介 1.1. 公司环境使用的puppet,但是我更喜欢ansible,原因有二,第一,我是红帽的忠粉:),第二,我对python比较熟悉 1.2. ansible官方网站:https://ww ...
- 【Java 8】Stream.distinct() 列表去重示例
在这篇文章里,我们将提供Java8 Stream distinct()示例. distinct()返回由该流的不同元素组成的流.distinct()是Stream接口的方法. distinct()使用 ...
- Spring Boot 自动扫描组件
使用@ComponentScan自动扫描组件 案例准备 1.创建一个配置类,在配置类上添加 @ComponentScan 注解.该注解默认会扫描该类所在的包下所有的配置类,相当于之前的 <con ...
- python数据预处理和特性选择后列的映射
我们在用python进行机器学习建模时,首先需要对数据进行预处理然后进行特征工程,在这些过程中,数据的格式可能会发生变化,前几天我遇到过的问题就是: 对数据进行标准化.归一化.方差过滤的时候数据都从D ...
- intelliJ破解及JavaEE搭建
intellij2020.3破解 转载自https://www.exception.site/essay/how-to-free-use-intellij-idea-2019-3 第一步: 下载最新的 ...