亲宝软件园·资讯

展开

.NET 6实现ActionFilter

CODE4NOTHING 人气:0

需求

Filter在.NET Web API项目开发中也是很重要的一个概念,它运行在执行MVC响应的Pipeline中执行,允许我们将一些可以在多个Action之间重用的逻辑抽取出来集中管理。虽然我们在上一篇使用.NET 6开发TodoList应用之实现接口请求验证中演示了如何通过使用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输出的返回数据日志:

总结

在本文中我们通过一个很简单的例子,演示了Action Filter的基本用法。至此我们关于请求中间件管道的讨论先告一个段落,后面说到认证鉴权的时候我们还会回来讨论这个主题。 

加载全部内容

相关教程
猜你喜欢
用户评论